将每一帧导出为电影文件中的图像(QuickTime-API)

时间:2009-12-07 11:23:47

标签: c++ export quicktime movie

我想打开现有的电影文件,并将此文件的每一帧导出为JPEG或TIFF等图像。到目前为止我到目前为止:

int main(int argc, char* argv[]) {
    char filename[255]; // Filename to ping.
    OSErr e;            // Error return.
    FSSpec filespec;    // QT file specification
    short filemovie;    // QT movie handle.
    Movie movie;        // QT movie "object".

    InitializeQTML(0);
    EnterMovies();
    // Because of QT's Mac origin, must convert C-string filename 
    // to Pascal counted string, then use that to make a filespec.
    c2pstr(filename); 
    FSMakeFSSpec(0, 0L, (ConstStr255Param)filename, &filespec);

    OpenMovieFile(&filespec, &filemovie, fsRdPerm);
    NewMovieFromFile(&movie, filemovie, nil, nil, newMovieActive, nil);
    ...

直到现在它工作正常(我用TimeValue movietime = GetMovieDuration(movie);测试并打印),但现在我想获得电影的每一帧并将其导出到一个文件中(首先,后来我只想保留内存中的数据可以使用它,但我必须知道它是否真的有效,所以现在导出到图像文件更好。)
我怎么做?我需要GWorld或PixMap吗?如何从电影文件中获取GWorld / PixMap,尤其是每一帧?

编辑:我的平台是WinXP

4 个答案:

答案 0 :(得分:1)

如果您只使用OS X,我会坚持使用QTKit API,因为它们的级别要高得多,而且通常更容易使用。

您想要做的一般要点是:

  1. 逐步浏览电影中的每一帧
  2. 获取当前帧的图像表示
  3. 将当前帧的图像保存到磁盘上的文件
  4. 要逐步浏览QuickTime影片中的帧,您可以使用QTKit中的QTMovie类执行此操作,如下所示:

    - (void)dumpFramesWithMovie:(QTMovie*)movie toFolder:(NSString*)folderPath
    {
        [movie setIdling:NO]; // Don't idle the movie
    
        [movie gotoEnd];
        QTTime endTime = [movie currentTime];
    
        [movie gotoBeginning];
    
        // Number of frames counted so far
        unsigned long numFrames = 0;
    
        // Turn off the Movie's looping so we are quaranteed to stop
        [movie setAttribute:[NSNumber numberWithBool:NO] forKey:QTMovieLoopsAttribute];
    
        // Construct a Dictionary of to use when reading frames from a movie
        NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
        [attributes setObject:QTMovieFrameImageTypeNSImage forKey:QTMovieFrameImageType];    
        while (true)
        {
            QTTime curTime = [movie currentTime];
            if (QTTimeCompare(curTime, endTime) == NSOrderedSame)
            {
                // Reached end of file
                break;
            }
    
            // Get the Current Frame as an NSImage
            NSImage* image = [movie frameImageAtTime:curTime 
                                      withAttributes:attributes error:nil];
    
            // Get the bitmap representation of this image
            // NOTE: This code assumes the first image representation is a NSBitmapImageRep, which is true
            // by default in OS X 10.5 and later.  
            // Production code should do error checking here.
            NSBitmapImageRep *bitmap = [[image representations] objectAtIndex: 0];
    
            // Construct a filename based upon the folder path and number of frames read so far
            NSString* fileName = [NSString stringWithFormat:@"%@/frame%d.png", folderPath, numFrames];
    
            // Get an PNG representation of this file
            NSData *data = [bitmap representationUsingType: NSPNGFileType
                                                properties: nil];
    
            // Write to disk
            [data writeToFile: fileName
                   atomically: NO];
    
            // Step to the next Frame
            [movie stepForward];
            numFrames++;
        }
    
        [movie gotoBeginning];
    }
    @end
    

    此代码已编译但尚未经过全面测试。

    使用此方法的一个警告是,在OS X 10.5及更早版本中,MPEG-1文件无法正确解码。据我所知,这已经定为10.6。此外,如果正在编写Windows应用程序,则需要使用较低的Quicktime-C API。

    在处理此问题时,请务必查看以下参考页:

答案 1 :(得分:1)

首先,关于电影出口商的这篇文章应该让你开始:

http://www.mactech.com/articles/mactech/Vol.16/16.05/May00QTToolkit/index.html

即使MacTech是Mac资源,所有描述的API函数也应该在QuickTime for Windows SDK中提供。

我会在找到时间后立即将一些示例代码拼凑在一起作为参考。

修改

有关其他信息,请参阅本书摘录:

QuickTime Toolkit - Basic Movie Playback and Media Types @ Google Books

编辑2 - 高级方法:电影出口商

如果您需要完成的只是从QuickTime影片中提取所有视频帧并将其转换为QuickTime API支持的其他格式,那么使用电影时无需采取任何低级操作出口

以下示例代码允许使用以编程方式调用的电影导出对话框,将QuickTime影片中的所有视频帧提取并转换为一堆JPEG文件。

只需在对话框的导出组合框中选择电影到图像序列,然后按选项选择所需的图像格式。

注1:如果您需要以非交互方式进行此操作,请告知我们。

注2:为清楚起见,省略了错误处理

#include "Movies.h"
#include "QTML.h"
#pragma comment (lib, "QTMLClient.lib")

...

int  flags                  = createMovieFileDeleteCurFile 
    | showUserSettingsDialog 
    | movieToFileOnlyExport;
ItemCount  movie_prop_count = 0;
CFStringRef  cfpath         = 0;
Boolean  bool_true          = true; 
QTNewMoviePropertyElement  movie_props[ 2 ];
Movie  movie;

// initialize QuickTime API
InitializeQTML( 0 );
EnterMovies();

// set up Core Foundation string for source path (argv[ 1 ]) contains the full path to the MOV file to convert
cfpath = CFStringCreateWithCString( 0, argv[ 1 ], kCFStringEncodingASCII );
movie_props[movie_prop_count].propClass        = kQTPropertyClass_DataLocation;
movie_props[movie_prop_count].propID           = kQTDataLocationPropertyID_CFStringNativePath;
movie_props[movie_prop_count].propValueSize    = sizeof(cfpath);
movie_props[movie_prop_count].propValueAddress = (void*)&cfpath;            
movie_props[movie_prop_count].propStatus       = 0;
++movie_prop_count;

// make Movie active
movie_props[movie_prop_count].propClass        = kQTPropertyClass_NewMovieProperty;
movie_props[movie_prop_count].propID           = kQTNewMoviePropertyID_Active;
movie_props[movie_prop_count].propValueSize    = sizeof(bool_true);
movie_props[movie_prop_count].propValueAddress = &bool_true;
movie_props[movie_prop_count].propStatus       = 0;
++movie_prop_count;

// aquire Movie for our Movie file
NewMovieFromProperties( movie_prop_count, movie_props, 0, 0, &movie );

// invoke conversion dialog
ConvertMovieToFile( movie, 0, 0, 0, 'TVOD', 0, 0, flags, 0 );

// clean up
DisposeMovie( movie );
CFRelease( cfpath );

ExitMovies();
TerminateQTML();

...

答案 2 :(得分:1)

这些命令行OSX实用程序非常擅长提取Quicktime影片的内容而无需购买QTPro:

qt_tools

答案 3 :(得分:0)

我通常只是将解码后的帧一个接一个地转储成二进制文件,然后使用一些YUV-Viewer来查看它们是否正常。为此,您必须知道解码帧的确切颜色格式和分辨率。如果您有RGB,那么肯定还有观众。

<强>更新

链接似乎不起作用。您将不得不谷歌搜索YUV查看器。或者,您可以从Elecard购买一个。