Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: AV_PES format - How can I detect frames?



Finally here's an even more detailed view into the AV_PES
data format. The attached program is able to identify
"Groups Of Pictures" as well as individual pictures.
Since the GOPs are optional they don't help much in
generating an index file into a recording, so I'll be
focusing on the actual pictures.

This is part of the ongoing work I am doing for my VDR project.
Just thought I'd post this in advance in case somebody else
is interested in this topic.

Klaus Schmidinger
-- 
_______________________________________________________________

Klaus Schmidinger                       Phone: +49-8635-6989-10
CadSoft Computer GmbH                   Fax:   +49-8635-6989-40
Hofmark 2                               Email:   kls@cadsoft.de
D-84568 Pleiskirchen, Germany           URL:     www.cadsoft.de
_______________________________________________________________
    [ Part 2: "Attached Text" ]

/*

This program detects the data blocks in an AV_PES data stream.

AV_PES data format:

'A'  'V'  t  n  'U'  g  ll  d d d ...

where

- '*' are literal characters
- t   is the type (1 = Video, 2 = Audio)
- n   is a sequence number (0..255, wrapping)
- g   is a "gap" number (don't know what it means)
- ll  is the two byte length of data (high byte first)
- d   is the actual video or audio data

*/

#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define SHOWBYTES 40
 
typedef unsigned char uchar;
typedef unsigned short ushort;

struct tAVPES {
  uchar AV[2];
  uchar t;
  uchar n;
  uchar U;
  uchar g;
  ushort ll;
  bool IsHeader(void) { return AV[0] == 'A' && AV[1] == 'V' && (t == 1 || t == 2) && U == 'U'; }
  ushort Length(void) { return ntohs(ll); }
  void Print(void) { printf("%c%c %d %3d %c %02X %5d", AV[0], AV[1], t, n, U, g, Length()); }
  };

bool ShowVideo = true;
bool ShowAudio = true;

int main(int argc, char *argv[])
{
  if (argc != 2) {
     fprintf(stderr, "usage: %s filename", argv[0]);
     return 1;
     }

  int f = open(argv[1], O_RDONLY);

  if (f >= 0) {
     unsigned char *d = NULL;
     tAVPES a;
     int r, skipped = 0;
     int largestBlock = 0, numSkips = 0, numVideoBlocks = 0, numAudioBlocks = 0, numUnknownBlocks = 0;
     while ((r = read(f, &a, sizeof(a))) == sizeof(a)) {
           if (a.IsHeader()) {
              if (skipped) {
                 fprintf(stderr, "*** skipped %d byte to sync on AV_PES header\n", skipped);
                 skipped = 0;
                 numSkips++;
                 }

              ushort l = a.Length();
              d = (unsigned char *)realloc(d, l);
              int rd;
              if ((rd = read(f, d, l)) == l) {
                 if (l > largestBlock)
                    largestBlock = l;
                 if (a.t == 1) {
                    numVideoBlocks++;
                    if (ShowVideo) {
                       bool printed = false;
                       for (int i = 0; i < l - 3; i++) {
                           if (d[i] == 0 && d[i + 1] == 0 && d[i + 2] == 1) {
                              // found start code
                              if (!printed) {
                                 a.Print();
                                 printed = true;
                                 for (int j = 0; j < SHOWBYTES; j++)
                                     printf(" %02X", d[j]);
                                 printf("\n");
                                 }
                              switch (d[i + 3]) {
                                case 0x00: // picture_start_code
                                           {
                                             unsigned short m = ntohs(*(short *)&d[i + 4]);
                                             printf("%*cpicture_header - temporal_reference: %4d  picture_coding_type: %d\n",
                                                    20, ' ', m >> 6, (m >> 3) & 0x07);
                                           }
                                           break;
                                case 0xB8: // group_start_code
                                           {
                                             unsigned long m = ntohl(*(long *)&d[i + 4]);
                                             printf("%*cgroup_of_pictures_header - time_code: %02d:%02d:%02d.%02d\n",
                                                    20, ' ', (m >> 26) & 0x1F, (m >> 20) & 0x3F, (m >> 13) & 0x3F, (m >> 7) & 0x3F);
                                           }
                                           break;
                                }
                              }
                           }
                       }
                    }
                 else if (a.t == 2) {
                    numAudioBlocks++;
                    if (ShowAudio) {
                       //TODO
                       }
                    }
                 else {
                    numUnknownBlocks++;
                    fprintf(stderr, "*** unknown block type\n");
                    }
                 }
              else
                 break;
              }
           else {
              lseek(f, -(r - 1), SEEK_CUR);
              skipped++;
              }
           }
     fprintf(stderr, "skips:   %d\n", numSkips);
     fprintf(stderr, "video:   %d\n", numVideoBlocks);
     fprintf(stderr, "audio:   %d\n", numAudioBlocks);
     fprintf(stderr, "unknown: %d\n", numUnknownBlocks);
     fprintf(stderr, "largest: %d\n", largestBlock);
     }
  else
     fprintf(stderr, "can't open '%s'\n", argv[1]);
  return 0;
}


Home | Main Index | Thread Index