2013년 4월 17일 수요일

ffmpeg file play source code

< FileReader.h >


extern "C" {
#include "libavcodec\avcodec.h"
#include "libavformat\avformat.h"
#include "libavutil\avutil.h"
}

class FileReader
{
public:    
    FileReader();
    virtual ~FileReader();

    int openFile(char *filename);
    void closeFile();
    int running();
    ...
    int seek(int pos);

protected:
    AVFormatContext *m_pFormatContext;
    AVPacket m_avPacket;
    AVIndexEntry *m_pIndexEntries;
    int m_nIndexEntries;

    enum CodecID m_nVideoCodecId;
    int m_nWidth, m_nHeight;
    int m_nVideoStreamId, m_nAudioStreamId;
    ...
    BOOL m_bReadThreadRun;
};


< FileReader.cpp >

#include "FileReader.h"

FileReader::FileReader()
{
    static int init = 0;
    if (init == 0)
    {
        WaitForSingleObject(hMutexCodec, INFINITE);
        av_register_all();
        ReleaseMutex(hMutexCodec);
        init = 1;
    }

    m_pFormatContext = NULL;

    m_nVideoStreamId = m_nAudioStreamId = AVMEDIA_TYPE_UNKNOWN;

    m_pIndexEntries = NULL;
    m_nIndexEntries = 0;

    m_bReadThreadRun = false;
}

FileReader::~FileReader()
{
    closeFile();
}

int FileReader::openFile(char *filepath)
{
    int err;

#ifdef FFMPEG_0_8
    err = av_open_input_file(&m_pFormatContext, filepath, NULL, 0, NULL);
#else
    err = avformat_open_input(&m_pFormatContext, filepath, NULL, NULL);
#endif

    if (err < 0) {
        printf("[%d] av_open_input_file: error %d\n", __FUNCTION__, err);
        return -2;
    }

    err = av_find_stream_info(m_pFormatContext);
    if (err < 0) {
        printf("[%d] av_find_stream_info: error %d\n", __FUNCTION__, err);
        closeFile();
        return -2;
    }

    av_init_packet(&m_avPacket);

    AVCodecContext *videoCodec = NULL;

    for (int i=0; i<m_pFormatContext->nb_streams; i++)
    {
        AVStream *stream = m_pFormatContext->streams[i];

        if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoCodec = stream->codec;
            m_nWidth = videoCodec->width;
            m_nHeight = videoCodec->height;

            m_pIndexEntries = stream->index_entries;
            m_nIndexEntries = stream->nb_index_entries;

            m_nVideoCodecId = videoCodec->codec_id;
            m_nVideoStreamId = stream->id;
        }
        else if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            m_nAudioStreamId = stream->id;
            ...
        }
    }

    return 0;
}

void FileReader::closeFile()
{
    if (m_pFormatContext) {
        av_free_packet(&m_avPacket);
        av_close_input_file(m_pFormatContext);
        m_pFormatContext = NULL;
        m_pIndexEntries = NULL;
        m_nIndexEntries = 0;
    }
}

int FileReader::running()
{
    int err;

    while (m_bReadThreadRun)
    {
        err = av_read_frame(m_pFormatContext, &m_avPacket);
        if (err < 0) 
        {
            Sleep(10);
            continue;
        }

        if (m_avPacket.stream_index == m_nVideoStreamId)
        {
            process video stream here...
        }
        else if (m_avPacket.stream_index == m_nAudioStreamId)
        {
            process audio stream here...
        }

        av_free_packet(&m_avPacket);
        Sleep(10);
    }

    return 0;
}

int FileReader::seek(int pos)
{
    if (m_pFormatContext)
        //return av_seek_frame(m_pFormatContext, m_nVideoStreamId, pos, AVSEEK_FLAG_BYTE);   // file position 으로 seek
        return av_seek_frame(m_pFormatContext, m_nVideoStreamId, pos, AVSEEK_FLAG_FRAME);    // frame count 로 seek

    return -1;
}