class FFMpegSourceModule : public SimpleModule {
public:
FFMpegSourceModule() : avFormatContext( 0 )
{
}
bool supportsOutputType( Format type )
{
return type == "FRAME_ID_MPEG1_VIDEO_PACKET" || type == "FRAME_ID_MPEG_AUDIO_PACKET" || type == "FRAME_ID_MPEG2_VIDEO_PACKET" || type == "FRAME_ID_MPEG4_VIDEO_PACKET";
}
const char* name() { return "FFMpeg Demuxer Source"; }
Format inputFormat() { return "FRAME_ID_URL_SOURCE"; }
Format outputFormat() { return "FRAME_ID_MULTIPLE_PACKET"; }
bool isBlocking() { return true; }
list<Module*> threadAffinity() { }
void init()
{
av_register_all();
}
void process( const Frame &frame )
{
printf("file: %s\n", (char*)frame.data());
// Open file
if ( av_open_input_file(&avFormatContext, (char*)frame.data(), 0, 0, 0) < 0 || !avFormatContext ) {
printf("error opening file");
return;
}
frame.deref();
// Gather stream information
if ( av_find_stream_info(avFormatContext) < 0 ) {
printf("error getting stream info\n");
return;
}
while( avFormatContext ) {
AVPacket *pkt = new AVPacket;
// if ( av_read_packet(avFormatContext, pkt) < 0 ) {
if ( av_read_frame(avFormatContext, pkt) < 0 ) {
printf("error reading packet\n");
av_free_packet( pkt );
delete pkt;
exit( 0 ); // EOF ?
} else {
AVCodecContext *context = &avFormatContext->streams[pkt->stream_index]->codec;
Frame *f = getAvailableFrame( context->codec_type );
if ( !f )
continue;
FFMpegStreamPacket *packet = (FFMpegStreamPacket*)f->data();
packet->packet = pkt;
//av_dup_packet( pkt );
ProcessMessages();
dispatch( routes[pkt->stream_index], Process, f );
}
}
exit( 0 );
}
Frame *getAvailableFrame( int type )
{
Frame *frame;
list<Frame*>::iterator it;
for ( it = used[type].begin(); it != used[type].end(); ++it ) {
frame = *it;
if ( frame->refcount() == 0 ) {
reuseFrame( frame );
frame->ref();
return frame;
}
}
// Create new frame
frame = createNewFrame( type );
if ( frame ) {
frame->ref();
used[type].push_back( frame );
}
return frame;
}
Frame* createNewFrame( int type )
{
FFMpegStreamPacket *packet = new FFMpegStreamPacket;
switch( type ) {
case CODEC_TYPE_AUDIO:
return new Frame( "FRAME_ID_MPEG_AUDIO_PACKET", packet );
case CODEC_TYPE_VIDEO:
return new Frame( "FRAME_ID_MPEG1_VIDEO_PACKET", packet );
}
return 0;
}
void reuseFrame( Frame *frame )
{
FFMpegStreamPacket *packet = (FFMpegStreamPacket*)frame->data();
av_free_packet( packet->packet );
delete packet->packet;
}
void connectTo( Module *next, const Frame &f )
{
routes[((FFMpegStreamPacket*)f.data())->packet->stream_index] = next;
}
private:
AVFormatContext *avFormatContext;
map<int,list<Frame*> > used;
map<int, Module*> routes;
};