Newer
Older
Import / research / pipeline / Modules / MpegDecodeModule.cpp
#include "Modules/SimpleModule.hpp"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"


class MpegDecodeModule : public SimpleModule {
public:
    MpegDecodeModule() : videoCodecContext( 0 )
    {           
        currentFrame = 0;
    }
    
    void init()
    {        
        av_register_all();
        
        if ( avcodec_open( videoCodecContext = avcodec_alloc_context(),  &mpeg1video_decoder ) < 0 ) {
            printf("error opening context\n");
            videoCodecContext = 0;
        }
    }

    void process( const Frame &frame ) 
    {
        AVPacket *pkt = ((FFMpegStreamPacket*)frame.data())->packet;

        if ( !videoCodecContext ) {
            printf("can't process video data without a context\n");
            return;
        }
        
        if ( !currentFrame )
            currentFrame = getAvailableFrame();
        
        YUVFrame *yuvFrame = (YUVFrame *)currentFrame->data();
        AVFrame *picture = yuvFrame->pic;
        
        assert( videoCodecContext->pix_fmt == PIX_FMT_YUV420P );
        
//printf("processing video data (%i x %i)\n", videoCodecContext->width, videoCodecContext->height);
        AVPacket *mpeg = pkt;
	unsigned char *ptr = (unsigned char*)mpeg->data;
        int count = 0, ret = 0, gotPicture = 0;
        // videoCodecContext->hurry_up = 2;
        int len = mpeg->size;
//        for ( ; len && ret >= 0; len -= ret, ptr += ret )
            ret = avcodec_decode_video( videoCodecContext, picture, &gotPicture, ptr, len );
        frame.deref();

        if ( gotPicture ) {
            yuvFrame->width = videoCodecContext->width;
            yuvFrame->height = videoCodecContext->height;
            yuvFrame->fmt = videoCodecContext->pix_fmt;
            SimpleModule::process( *currentFrame );
            currentFrame = 0;            
        }
    }
    
    Frame* createNewFrame()
    {
        YUVFrame *yuvFrame = new YUVFrame;
        yuvFrame->pic = avcodec_alloc_frame();
        return new Frame( "FRAME_ID_YUV_VIDEO_FRAME", yuvFrame );
    }
    
    void reuseFrame( Frame *frame )
    {
        YUVFrame *yuvFrame = (YUVFrame *)frame->data();
        av_free( yuvFrame->pic );
        yuvFrame->pic = avcodec_alloc_frame();
    }
    
    const char *name() { return "Mpeg1 Video Decoder"; }
    Format inputFormat() { return "FRAME_ID_MPEG1_VIDEO_PACKET"; }
    Format outputFormat() { return "FRAME_ID_YUV_VIDEO_FRAME"; }
    bool isBlocking() { return true; }

private:
    Frame *currentFrame;
    AVCodecContext *videoCodecContext;
};