On Fri, 2 May 2008, Thomas Richards wrote:

> I now have a first-pass solution working. Basically I iterate over the 
> entire file, and count the number of times I get STATE_PICTURE from the 
> mpeg2_parse function.
>
> This works, but it's horribly slow. A 24 minute clip (400 MB on disk) 
> takes over a minute to parse (84 seconds).

> I was hoping someone here would know a few tricks to speed up this 
> performance. One thing I have thought of is increasing the size of my 
> memory buffer from 4KB to some larger value, but it doesn't seem to help 
> that much (using 8KB reduces the time from 84 to 81 seconds).

Hi Thomas,

Certainly, decoding the entire stream with libmpeg2 is not going to get 
you the best performance if you just want to measure the duration. 
Experimenting with mpeg2_skip() will probably speed things up, but a 
dedicated program to do this will probably be faster still.

And mmap()ing the file will probably improve performance as well.

Also keep in mind -- counting Pictures is not enough. You need to count 
frames. A Picture can last 0.5, 1, 1.5, 2, or 3 frames, depending on 
progressive_sequence, picture_structure, progressive_frame, 
top_field_first, and repeat_first_field. (libmpeg2 helpfully does all the 
logic and puts it in the nb_fields field.)

Here's a simple example program that does this standing alone. On a 3 GHz 
Pentium 4, it takes about 4.1 seconds to do a 1 GB, 35,919-picture, 
1,498-second slice from a DVD. That's about 27 times faster than libmpeg2 
decoding the whole thing.

http://web.mit.edu/keithw/www/mpegduration.c

(On 32-bit Linux, the example only works on files smaller than 2 GB.)

Regards,
Keith

========================

/* http://web.mit.edu/keithw/www/mpegduration.c */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/* compile with: gcc -g -Wall -O2 -o mpegduration mpegduration.c */

/* MPEG-2 tables */
const char type[ 4 ] = { 'X', 'I', 'P', 'B' };
const double frame_rate_value[ 9 ] = { 0, 24000.0/1001.0, 24, 25,
                                       30000.0/1001.0, 30, 50, 60000.0/1001.0,
                                       60 };

/* Check for picture start code */
inline int picture_coding_extension_start_code( uint8_t *buf ) {
   if ( (buf[ 0 ] == 0) &&
        (buf[ 1 ] == 0) &&
        (buf[ 2 ] == 1) &&
        (buf[ 3 ] == 0xB5) &&
        ((buf[ 4 ] >> 4) == 8) )
     return 1;

   return 0;
}

/* Check for sequence header code */
inline int sequence_header_code( uint8_t *buf ) {
   if ( (buf[ 0 ] == 0) &&
        (buf[ 1 ] == 0) &&
        (buf[ 2 ] == 1) &&
        (buf[ 3 ] == 0xB3) )
     return 1;

   return 0;
}

/* Check for sequence extension start */
inline int sequence_extension_start_code( uint8_t *buf ) {
   if ( (buf[ 0 ] == 0) &&
        (buf[ 1 ] == 0) &&
        (buf[ 2 ] == 1) &&
        (buf[ 3 ] == 0xB5) &&
        ((buf[ 4 ] >> 4) == 1) )
     return 1;

   return 0;
}

int main( int argc, char *argv[] ) {
   int fd;
   uint8_t *mpeges;
   struct stat thestat;
   off_t i = 0;
   char progressive_sequence = 0;
   uint8_t frame_rate_code = 0;
   char frame_rate_extension_n = 0, frame_rate_extension_d = 0;
   char sequence_header_hit = 0, sequence_extension_hit = 0;
   int pictures = 0;
   double seconds = 0;
   double frame_rate = 0;
   double field_duration = 0;

   /* Check arguments */
   if ( argc != 2 ) {
     fprintf( stderr, "Usage: %s FILENAME\n", argv[ 0 ] );
     exit( 1 );
   }

   /* Open MPEG-2 video elementary stream */
   /* On a 32-bit system, this will not open files bigger than 4 GB. */
   fd = open( argv[ 1 ], O_RDONLY );
   if ( fd < 0 ) {
     perror( "open" );
     exit( 1 );
   }

   /* Get size of file */
   if ( fstat( fd, &thestat ) < 0 ) {
     perror( "fstat" );
     exit( 1 );
   }

   /* Memory-map file */
   mpeges = mmap( NULL, thestat.st_size, PROT_READ, MAP_SHARED, fd, 0 );
   if ( mpeges == MAP_FAILED ) {
     perror( "mmap" );
     exit( 1 );
   }

   /* Iterate through every byte of file */
   while( i < thestat.st_size - 10 ) {
     if ( sequence_header_code( mpeges + i ) ) {
       /* Get first part of frame rate from the Sequence header */
       frame_rate_code = mpeges[ i + 7 ] & 0x0F;

       sequence_header_hit = 1;
     } else if ( sequence_header_hit
                && sequence_extension_start_code( mpeges + i ) ) {
       /* From Sequence extension, get progressive_sequence and */
       /* other components of true frame rate. */
       /* (Streams at common frame rates leave these at 0.) */
       progressive_sequence = (mpeges[ i + 5 ] >> 3) & 0x01;
       frame_rate_extension_n = (mpeges[ i + 9 ] >> 5) & 0x03;
       frame_rate_extension_d = mpeges[ i + 9 ] & 0x1F;

       frame_rate = frame_rate_value[ frame_rate_code ]
        * (frame_rate_extension_n + 1.0) / (frame_rate_extension_d + 1.0);
       field_duration = 0.5 / frame_rate;

       sequence_extension_hit = 1;
     } else if ( sequence_header_hit
                && sequence_extension_hit
                && picture_coding_extension_start_code( mpeges + i ) ) {
       /* Get variables from Picture coding extension */
       /* These determine duration of picture */
       int picture_structure, top_field_first,
        repeat_first_field, progressive_frame;
       int fields = -1;
       int frame_picture = 0;

       picture_structure = mpeges[ i + 6 ] & 0x03;
       top_field_first = mpeges[ i + 7 ] >> 7;
       repeat_first_field = (mpeges[ i + 7 ] >> 1) & 0x01;
       progressive_frame = mpeges[ i + 8 ] >> 7;

       if ( picture_structure == 3 ) frame_picture = 1;

       /* Calculate how many fields picture is */
       if ( frame_picture == 0 ) {
        fields = 1;
       } else if ( progressive_sequence ) {
        if ( repeat_first_field == 0 ) fields = 2;
        if ( (repeat_first_field == 1) && (top_field_first == 0) ) fields = 4;
        if ( (repeat_first_field == 1) && (top_field_first == 1) ) fields = 6;
       } else { /* interlaced sequence */
        if ( progressive_frame == 0 ) fields = 2;
        if ( (progressive_frame == 1) && (repeat_first_field == 0) ) fields = 2;
        if ( (progressive_frame == 1) && (repeat_first_field == 1) ) fields = 3;
       }

       if ( fields == -1 ) {
        fprintf( stderr, "Warning: illegal flags on picture #%d\n", pictures );
       } else {
        seconds += field_duration * fields;
       }

       pictures++;
     }

     i++;
   }

   printf( "MPEG-2 file contained %d pictures. Total duration: %.3f seconds.\n",
          pictures, seconds );

   return 0;
}

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
Libmpeg2-devel mailing list
Libmpeg2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libmpeg2-devel

Reply via email to