Export every frame as image from a Movie-File (

2019-02-16 02:22发布

问题:

I want to open an existing Movie-File and export every frame of this file to an image like JPEG or TIFF. I got so far until now:

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);
    ...

Until now it works fine (I tested with TimeValue movietime = GetMovieDuration(movie); and print it), but now I want to get every frame of the movie and export it to a file (for first, later i just want to keep the data in memory to work with it, but i have to know if it really works, so export to an image-file is better for now).
How do I do that? Do I need a GWorld or a PixMap? How do I get a GWorld/PixMap from a Movie-File, especially each frame of it?

edit: My Platform is WinXP

回答1:

As a beginning, this article on Movie exporters should pretty much get you started:

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

Even though MacTech is a Mac resource, all described API functions should be available in the QuickTime for Windows SDK as well.

I will slap some sample code together myself as a reference here as soon as I find the time.

Edit

See this book excerpt for additional info:

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

Edit 2 - The High-Level Approach: Movie Exporters

If all you need to accomplish is to extract all video frames from a QuickTime Movie and convert them to another format supported by the QuickTime API you won't have to take any low-level actions whatsoever if using a Movie Exporter.

The below sample code allows to extract and convert all video frames from a QuickTime Movie to, f.e., a bunch of JPEG files using a programmatically invoked Movie Export Dialog.

Just select Movie to Image Sequence in the Export combo box of the dialog and select your desired image format by hitting Options.

Note 1: If you need to do this non-interactively, just let me know.

Note 2: error handling has been omitted for clarity

#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:

If you are working on OS X only I would stick with the QTKit APIs because they are much higher level and generally easier to work with.

The general gist of what you want to do is:

  1. Step Through each frame in a movie
  2. Get a image representation for the current frame
  3. Save the current frame's image to a file on disk

To step through the frames in a QuickTime movie, you can use the QTMovie class in QTKit to do this as follows:

- (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

This code compiles but has not been fully tested.

One caveat with this approach is that MPEG-1 files will not decode properly on OS X 10.5 and earlier. This has been fixed as of 10.6 as far as I know. Also, if are writing a Windows application, you'll need to use the lower lever Quicktime-C APIs.

Be sure to check the following reference pages while working on this:

  • QTKit Application Programming Guide
  • QTKit Frequently Asked Questions
  • QTMovie Class Reference
  • Quickies for NSImage
  • NSBitmapImageRep Reference
  • NSImage Reference


回答3:

These command line OSX utilities are really good at extracting the contents of a Quicktime movie without having to buy QTPro:

qt_tools



回答4:

I usually just dump the decoded frames into a binary one after another and then use some YUV-Viewer to see if they look Ok. For that you have to know the exact color format and resolution of the decoded frames. If you have RGB, there are certainly also viewers for that.

UPDATE:

Link doesn't seem to work. You will have to google for a YUV-Viewer. Alternatively, you can buy one from Elecard.