Maker Pro
Maker Pro

MPEG2 Audio and Video Splitter

I am using an Altera FPGA to split video and audio data from an *.mpg
file. I receive mpg data and send to a IP MPEG2 Decoder Core
purchased from Amphion Semiconductors. I have attempted to code a
data splitter but have plenty of questions with the demultiplexing of
the data.

The below describes the code at higher level:

if (prefix_code_recognized) // received 24'h000001
start_code <= next_data_byte;

if ((8'h00 <= start_code <= 8'BF) ||
(8'hE0 <= start_code <= 8'hFF))
video_start_code <= 1'b1;

if (8'hC0 <= start_code <= 8'hDF)
audio_start_code <= 1'b1;

Once I have decoded a video start code, I send all data to the Video
Decoder, until I recognize a prefix followed by an audio start code,
when I then send data to the audio decoder core until Video start_code
is recognized.

To test my splitter I input an mpg file into the stimulus and split
the data out, writing the video contents to a file. I then convert
the dump file to an mpg file and play in media player. If the
splitter is working, then the file would play w/out sound. However, I
only get a black screen which tells me the code is not functioning
correctly.

Can someone please point me in the right direction? Thanks.

Amit
 
B

Ben Jackson

Jan 1, 1970
0
I am using an Altera FPGA to split video and audio data from an *.mpg
file.

What is the format of your *.mpg file? It is almost certainly either
a mpeg2 transport stream or a packetized elementary stream. Either way,
you will find start codes inside, but you will be looking "inside"
the TS or PES packets and your output will be a hash.

A TS will start with 0x47 (and repeat every 188 bytes). I forget if
there's anything special about a PES, but knowing it exists is half the
battle. Either one will have enough information to allow you to split
the file at a higher level than the individual start codes.

BTW, are you the Amit Patel I know?
 
What is the format of your *.mpg file? It is almost certainly either
a mpeg2 transport stream or a packetized elementary stream. Either way,
you will find start codes inside, but you will be looking "inside"
the TS or PES packets and your output will be a hash.

A TS will start with 0x47 (and repeat every 188 bytes). I forget if
there's anything special about a PES, but knowing it exists is half the
battle. Either one will have enough information to allow you to split
the file at a higher level than the individual start codes.

BTW, are you the Amit Patel I know?

Hello Ben,

Thank you for your response. I believe the data is PES, because the
stream starts with a start_code of 32'h000001BA. I am using an IP
MPEG2 Video Decoder in my design, and I need to split the mpeg2 video
and audio data. I am doing so as shown above, but am still uncertain
if this is the proper way to transmit the data. Do I have to go by
the packet information and count my data? Below is a C++ description
I am following. Let me know what you think. Thanks:

#include <windows.h>
#include <stdio.h>
#include "MpegStream.h"

void MpegWrite(char* fname, HANDLE hFile, LPBYTE base, DWORD len,
LPDWORD count, BYTE c)
{
base[*count] = c;
if (++*count >= len)
{
DWORD dwBytesWritten;
if (!WriteFile(hFile, base, len, &dwBytesWritten, NULL))
{
LPVOID errmsg;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, (LPSTR)&errmsg, 0,
NULL);
fprintf(stderr, "WriteFile %s failure (%d) %s\n", fname,
GetLastError(), errmsg);
LocalFree(errmsg);
ExitProcess(1);
}
*count = 0;
}
}

int main(int argc, char* argv[])
{
LPVOID errmsg;
BYTE cMpegBuf[1024];
BYTE cVideoBuf[1024];
BYTE cAudioBuf[1024];
LPBYTE lpMpeg;
DWORD dwMpeg;
DWORD dwVideo;
DWORD dwAudio;
DWORD dwVES;
DWORD dwAES;

// check command line arguments
if (argc != 4)
{
fputs("Usage: MpegSplitter <input MPG> <output video> <output audio>
\n", stderr);
ExitProcess(1);
}

// open input MPG file
HANDLE hMpeg = CreateFile(argv[1], GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (hMpeg == (HANDLE)INVALID_HANDLE_VALUE)
{
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, (LPSTR)&errmsg, 0,
NULL);
fprintf(stderr, "CreateFile %s failure (%d) %s\n", argv[1],
GetLastError(), errmsg);
LocalFree(errmsg);
ExitProcess(1);
}

// create output video file
HANDLE hVideo = CreateFile(argv[2], GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, 0, NULL);
if (hVideo == (HANDLE)INVALID_HANDLE_VALUE)
{
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, (LPSTR)&errmsg, 0,
NULL);
fprintf(stderr, "CreateFile %s failure (%d) %s\n", argv[2],
GetLastError(), errmsg);
LocalFree(errmsg);
ExitProcess(1);
}

// open input MPG file
HANDLE hAudio = CreateFile(argv[3], GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, 0, NULL);
if (hAudio == (HANDLE)INVALID_HANDLE_VALUE)
{
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, (LPSTR)&errmsg, 0,
NULL);
fprintf(stderr, "CreateFile %s failure (%d) %s\n", argv[3],
GetLastError(), errmsg);
LocalFree(errmsg);
ExitProcess(1);
}

// split mpeg into video and audio
lpMpeg = cMpegBuf;
dwMpeg = 0;
dwVideo = 0;
dwAudio = 0;
dwVES = 0;
dwAES = 0;

int state = 1;
while (1)
{
// if need mpeg data
if (dwMpeg == 0)
{
if (!ReadFile(hMpeg, cMpegBuf, sizeof(cMpegBuf), &dwMpeg, NULL))
{
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, (LPSTR)&errmsg, 0,
NULL);
fprintf(stderr, "ReadFile %s failure (%d) %s\n", argv[1],
GetLastError(), errmsg);
LocalFree(errmsg);
ExitProcess(1);
}
if (dwMpeg == 0)
break;
lpMpeg = cMpegBuf;
}

// process mpeg data
switch (state)
{
case 1 : // look for first byte of start code
if (*lpMpeg == 0)
state = 2;
else
{
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
*lpMpeg);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
*lpMpeg);
}
break;

case 2 : // look for second byte of start code
if (*lpMpeg == 0)
state = 3;
else
{
state = 1;

MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
0);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
*lpMpeg);

MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
0);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
*lpMpeg);
}
break;

case 3 : // look for third byte of start code
if (*lpMpeg == 1)
state = 4;
else if (*lpMpeg != 0)
{
state = 1;

MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
0);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
0);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
*lpMpeg);

MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
0);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
0);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
*lpMpeg);
}
break;

case 4 : // have start code. process start code
// if start of video elementary stream
if (*lpMpeg >= VIDEO_ELEMENTARY_STREAM &&
*lpMpeg < VIDEO_ELEMENTARY_STREAM + 0x10) //
VIDEO_ELEMENTARY_STREAM == 0xE0
{
state = 5;

MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
0);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
0);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
1);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
*lpMpeg);
}
// if start of audio elementary stream
else if (*lpMpeg >= AUDIO_ELEMENTARY_STREAM &&
*lpMpeg < AUDIO_ELEMENTARY_STREAM + 0x20) //
AUDIO_ELEMENTARY_STREAM == 0xC0
{
state = 8;

MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
0);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
0);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
1);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
*lpMpeg);
}
// if none of the above
else
{
state = 1;

MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
0);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
0);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
1);
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
*lpMpeg);

MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
0);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
0);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
1);
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
*lpMpeg);
}
break;

case 5 : // here for MSB of VES byte count
dwVES = *lpMpeg << 8;
state = 6;
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
*lpMpeg);
break;

case 6 : // here for LSB of VES byte count
dwVES |= *lpMpeg;
state = 7;
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
*lpMpeg);
break;

case 7 : // here to copy VES data
if (--dwVES == 0)
state = 1;
MpegWrite(argv[2], hVideo, cVideoBuf, sizeof(cVideoBuf), &dwVideo,
*lpMpeg);
break;

case 8 : // here for MSB of AES byte count
dwAES = *lpMpeg << 8;
state = 9;
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
*lpMpeg);
break;

case 9 : // here for LSB of AES byte count
dwAES |= *lpMpeg;
state = 10;
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
*lpMpeg);
break;

case 10 : // here to copy AES data
if (--dwAES == 0)
state = 1;
MpegWrite(argv[3], hAudio, cAudioBuf, sizeof(cAudioBuf), &dwAudio,
*lpMpeg);
break;
}

// decrement mpeg buffer count
lpMpeg++;
dwMpeg--;
}

// close files
CloseHandle(hMpeg);
CloseHandle(hVideo);
CloseHandle(hAudio);

return(0);
}
 
Top