1

我想打开一个现有的电影文件并将该文件的每一帧导出为 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

4 回答 4

1

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

您想要做的一般要点是:

  1. 逐帧浏览电影中的每一帧
  2. 获取当前帧的图像表示
  3. 将当前帧的图像保存到磁盘上的文件中

要逐步浏览 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

此代码可以编译,但尚未经过全面测试。

这种方法的一个警告是 MPEG-1 文件在 OS X 10.5 和更早版本上无法正确解码。据我所知,这已在 10.6 中修复。此外,如果正在编写 Windows 应用程序,您将需要使用较低级别的 Quicktime-C API。

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

于 2009-12-07T19:50:18.253 回答
1

作为开始,这篇关于电影导出器的文章应该可以帮助您入门:

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

尽管 MacTech 是 Mac 资源,但所有描述的 API 函数也应该在 QuickTime for Windows SDK 中可用。

我一有时间就会自己拼凑一些示例代码作为参考。

编辑

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

QuickTime Toolkit - 基本电影播放和媒体类型 @ Google 图书

编辑 2 - 高级方法:电影导出器

如果您需要完成的只是从 QuickTime 电影中提取所有视频帧并将它们转换为 QuickTime API 支持的另一种格式,那么如果使用Movie Exporter,您将无需采取任何低级操作。

下面的示例代码允许使用以编程方式调用的电影导出对话框从 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();

...

于 2009-12-21T14:18:25.753 回答
1

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

qt_tools

于 2011-09-29T20:25:04.027 回答
0

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

更新:

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

于 2009-12-07T11:31:09.270 回答