织梦CMS - 轻松建站从此开始!

罗索

mp4 Source filter的基本思路

jackyhwei 发布于 2011-09-18 01:04 点击:次 
其 实CSourceStream就是一个线程和outpin的综合体,再filter代码的某个地方创建这样的一个class CSourceStream,就相当于给他添加了一个outputpin,一般如果要实现seek功能,这个CSeek一般是和 CSourceStream在一起的,因为每一种媒体的seek方式都是不同的
TAG:

首先,当我们的source fiter只是支持音频或视频中的一种的时候,有的时候要是有音视频混合的时候呢?
这就要求,我们的CSource和CSourceStream分开,CSource检测好了媒体类型的时候再去动态地创建CSourceStream,我们可以看一下CSourceStream的一个本质:
class CSourceStream : public CAMThread, public CBaseOutputPin
其 实CSourceStream就是一个线程和outpin的综合体,再filter代码的某个地方创建这样的一个class CSourceStream,就相当于给他添加了一个outputpin,一般如果要实现seek功能,这个CSeek一般是和 CSourceStream在一起的,因为每一种媒体的seek方式都是不同的,一个CSourceStream对应一个媒体流,那么也必然对应唯一的 seek,因而你可以为你的output接口建立一个单独地对象如:
class CMP4ParserAudioOp : public CSourceStream, public CSourceSeeking

class CMP4ParserVideoOp : public CSourceStream, public CSourceSeeking
因为这里我的filter有音频也有视频,因而我们要做的事情就是创建两个这样的类,在SourceFilter在Load的时候就去根据我们的文件类型去 new 这样的类,我们的 pin就可以出来,这里你有多少new  就由多少输出的pin,有人或许会问,这个pin难道就自动指给了source filter,因为pin只有和filter相关连才能起作用?我的回答是,那是当然,我们可以看看我的代码,因为我们的source是一个这样的类
class CMP4ParserFilter : public CSource, public IFileSourceFilter

其实这样一项所谓的seek功能,实际上不是filter做的,而是filter的outputpin做的,难怪以前看书看到dshow消息的传递都是pin之间的传递。

这里,因为是public IFileSourceFilter是sourcefilter一定要实现的类,他有两个重要的函数

HRESULT Load(  LPCOLESTR pszFileName,  const AM_MEDIA_TYPE* pmt);和

HRESULT GetCurfile(  LPOLESTR* ppszFileName,  AM_MEDIA_TYPE* pmt);

很有趣的两个函数,我们可以看看他们的说明,首先是GetCurfile,我们可以查看MSDN可以看到,这两个居然都是输出,就是调用这个函数之 前,我们是不知道任何关于这个文件的信息,甚至我们打开的文件都不知道。因而我们可以确定,这个函数一定先于load调用,首先是得到文件的名字和文件类 型才能去加载文件。

好,我们看看程序中GetCurfile是如何实现的?

  1. STDMETHODIMP CMP4ParserFilter::GetCurFile(LPOLESTR *ppwszFileName, AM_MEDIA_TYPE *pmt) 
  2.     //输入的都是指针,因为两个参数本身就是输出  
  3.     CheckPointer(ppwszFileName, E_POINTER);  
  4.     *ppwszFileName = NULL;  
  5.     if (m_pwFileName != NULL)   
  6.     {  
  7.        DWORD dwSize = sizeof(WCHAR) * (1 + lstrlenW(m_pwFileName));    
  8.       *ppwszFileName = (LPOLESTR)CoTaskMemAlloc(dwSize);  
  9.       if (*ppwszFileName != NULL)    
  10.       {  
  11.            CopyMemory(*ppwszFileName, m_pwFileName, dwSize);   
  12.       }  
  13.     }  
  14.     return S_OK; 

上面的函数就是把我的一个成员拷贝到ppwszFileName中,这里还为ppwszFileName分配了空间。这里似乎没有做媒体类型的类型的拷贝,为什么我们可以看看后面的代码,首先,我们得到媒体类型是因为我们要进行后面的操作。

这里一个成员变量是什么时候赋值的呢?
我晕,居然这个成员变量是在Load中赋值的,那么我们推翻前面的论断,这里的getcurfile就相当于一个Get类型的函数,我们的东西都准备好了,然后要获得其中的一些属性,这个Get类型的函数将相当于一个只读不写的函数。那我们的file从那里来的呢?
我 们只能把这个工作给Graph,我们的Graph有四个方法加载Source,如RendFile 或者AddSource,这些个函数首先调用的是系统的一些东西或者指定的函数名,如在rendfile的时候一定要有一个参数输入,在 AddSourceFilter也要涉及到文件名,即使在GraphEdit中,我们纯粹的添加一个SourceFilter都会弹出来一个对话框问你我 们要打开什么文件。当然,如果你的Source打开的文件是固定的,如一些网路Source,我的Filter就只是打开某个IP的某个协议下的某个文 件,这样就可以在里面取常值,怎么做后面在来.

既然这样,我们可以看看我们的Load函数,因为得到了文件名,下面就是由文件名得到文件的一些信息了:

STDMETHODIMP CMP4ParserFilter::Load(LPCOLESTR pwszFileName, const AM_MEDIA_TYPE *pmt)
{
      if (m_pwFileName)
        return E_FAIL;
// 如果已经有m_pwFileNam,这个基本不可能,因为我们初始化的时候m_pwFileNam为null,然后通过Graph调用得到 pwszFileName之后,我们就直奔Load函数了,我们是准备在Load里面给m_pwFileName赋值的,这里m_pwFileName已 经有值,就证明Load已经调用过了,可以直接返回了。

//如果没有值,那么

CheckPointer(pwszFileName, E_POINTER);

    // lstrlenW is one of the few Unicode functions that works on win95
    DWORD dwSize = lstrlenW(pwszFileName) + 1;

#ifndef UNICODE
    TCHAR *pszFileName = 0;
    pszFileName = new char[dwSize * 2];
    if (!pszFileName)
        return E_OUTOFMEMORY;

    WideCharToMultiByte(GetACP(), 0, pwszFileName, -1,
        pszFileName, dwSize * 2, NULL, NULL);
#else
   TCHAR pszFileName[MAX_PATH] = {0};
    lstrcpy(pszFileName, pwszFileName);
#endif
首先是进行转化,传进来的是一个LPCOLESTR,我们看看是一个OLE的字符串,编码未定,首先得到长度,然后转化到我们的pszFileName中。

// file checking and identify the video & audio codec
    HRESULT  hr = CheckFile(pszFileName);
然后判断文件是否存在,是否使我们想要的媒体格式文件,这个checkfile中做了很多事情,我们这里我们让大家比较好的了解程序的框架,这一块放到后面去说。check之后,返回一个hr。
#ifndef UNICODE
    delete[] pszFileName;
#endif

    if (FAILED(hr))
        return E_FAIL;
下面就是很有趣的代码,我们checkfile中肯定读取了文件头,得到了文件的相应的信息,下面就是一个创建Pin的过程,我们的文件要有音频还是视频,还是二者都有
//首先是视频

    ///////////////////////////////////////////
    // Add Output Pin for Video Stream
    int        b;
    switch (m_video_codec) {
    case RAW_STRM_TYPE_M4V:            // MPEG4
    case RAW_STRM_TYPE_H263:
printf("/n[VIDEO] MPEG4, profile = 0x%02X", m_video_profile);
        MakeVideoMediaType(&m_video_mt);
        new CMP4ParserVideoOp(&hr, this, L"Video Out");
        break;

    case RAW_STRM_TYPE_H264RAW:        // H264
printf("/n[VIDEO] H.264, profile = 0x%02X", m_video_profile);
        if (m_video_profile == 66) {    // It supports H.264 Baseline only..
            MakeVideoMediaType(&m_video_mt);
            new CMP4ParserVideoOp(&hr, this, L"Video Out");
        }
        else
            m_video_codec = MP4_INVALID_TRACK_ID;
        break;

    default:
        break;
    }

和我们前面说的差不多,new了一个outpin,所属的filter指向了this。
但是这里多做了事情,就是MakeVideoMediaType,注意我们并不是支持所有的H264,只是支持其中的一种。

  1. HRESULT CMP4ParserFilter::MakeVideoMediaType(CMediaType *pMediaType) 
  2.     unsigned int  *size; 
  3.  
  4.     pMediaType->InitMediaType(); 
  5.     pMediaType->SetType(&MEDIATYPE_Stream); 
  6.  
  7.     switch (m_video_codec) { 
  8.     case RAW_STRM_TYPE_M4V: 
  9.     case RAW_STRM_TYPE_H263: 
  10.         pMediaType->SetSubtype(&MEDIASUBTYPE_m4v); 
  11.         break
  12.  
  13.     case RAW_STRM_TYPE_H264RAW: 
  14.         pMediaType->SetSubtype(&MEDIASUBTYPE_h264raw); 
  15.         break
  16.  
  17.     default
  18.         RETAILMSG(1, (L"[SSAP MP4Parser]unsupported file type/n")); 
  19.         return E_FAIL; 
  20.     } 
  21.  
  22.     size = (unsigned int *) pMediaType->ReallocFormatBuffer(sizeof(unsigned int) * 2); 
  23.     size[0] = m_video_width; 
  24.     size[1] = m_video_height; 
  25.  
  26.     pMediaType->SetFormat((BYTE *)size, sizeof(unsigned int) * 2); 
  27.  
  28.     return S_OK; 

上面是vedio的创建,如果我们的文件还有音频,那么我们还要new一个音频的pin
///////////////////////////////////////////
    // Add Output Pin for Audio Stream
    switch (m_audio_codec) {
    case RAW_STRM_TYPE_M4A:            // MPEG4-AAC
        MakeAudioMediaType(&m_audio_mt);
        new CMP4ParserAudioOp(&hr, this, L"Audio Out");
        break;

    case RAW_STRM_TYPE_AMR_NB:        // AMR-NB
        MakeAudioMediaType(&m_audio_mt);
        new CMP4ParserAudioOp(&hr, this, L"Audio Out");
        break;

    default:
        break;
    }

// Restore the current file name
    m_pwFileName = new WCHAR[dwSize];

    if (m_pwFileName != NULL)
        CopyMemory(m_pwFileName, pwszFileName, dwSize * sizeof(WCHAR));

    return S_OK;

}
这样,一个load就完了,其实也不难,总结一下,分析文件-》创建outpin-》存一些媒体相关的属性,其中在分析文件的时候就作了很多存储媒体属性的事情呢。

下面我们来看一下,如何checkfile,这里用了一个开源的东东,mpeg4ip4v2,专门用来解析此类文件的。

在checkfile之前,我们定义一个函数,把宽字符的wchar * 转换为 char *
static void wchar_t2char(const wchar_t *str_wchar, char *str_char)
{
    int        i, j;
    int        leng;
    wchar_t    c;

    leng = wcslen(str_wchar);
    for (i=j=0; i<leng; i++, j++)
    {
        c = str_wchar[i];
        if (c == 0) {
            str_char[j] = '/0';
            break;
        }
        else if (c < 0x80) {
            str_char[j] = (char)str_wchar[i];
        }
        else {
            // Currently the non-alphanumeric characters are not supported.
            str_char[j] = '/0';
            break;
        }
    }

    str_char[j] = '/0';
}
然后就是我们函数的主体了
//
// ReadTheFile
//
HRESULT CMP4ParserFilter::CheckFile(LPCTSTR pszFileName)
{
    char      *video_name, *audio_name;
    char       filename[256];


    ///////////////////////////////////////////////
    /////                                     /////
    /////  1. Open the mp4 file for reading.  /////
    /////                                     /////
    ///////////////////////////////////////////////
    wchar_t2char(pszFileName, filename);
//printf("/n(CMP4ParserFilter::CheckFile) filename=%s.", filename);
//    m_hMP4File = MP4Read(filename, 0);
RETAILMSG(1, (L"/n(CMP4ParserFilter::CheckFile) filename=%s.", pszFileName));
    m_hMP4File = MP4ReadWchar(pszFileName, 0);
    if (!m_hMP4File)
        return E_FAIL;

    RETAILMSG(1, (L"/n MP4Read succeed.."));
//首先是读取文件
//然后是储存一些参数
    /////////////////////////////////////////////////////////
    /////                                               /////
    /////  2. Identify the video & get its properties.  /////
    /////                                               /////
    /////////////////////////////////////////////////////////
    m_video_trId = MP4FindTrackId(m_hMP4File, 0, MP4_VIDEO_TRACK_TYPE, 0);
    if (m_video_trId != MP4_INVALID_TRACK_ID) {

        video_name = (char *) MP4GetTrackMediaDataName(m_hMP4File, m_video_trId);
        if (strcmp(video_name, "mp4v") == 0)
            m_video_codec = RAW_STRM_TYPE_M4V;        // MPEG4
        else if (strcmp(video_name, "s263") == 0)
            m_video_codec = RAW_STRM_TYPE_H263;        // H.263
        else if (strcmp(video_name, "avc1") == 0)
            m_video_codec = RAW_STRM_TYPE_H264RAW;    // H.264
        else
            m_video_codec = 4;    // Unknown

        // Timescale (ticks per second) and duration of the Video track
        m_video_timescale       = MP4GetTrackTimeScale(m_hMP4File, m_video_trId);
        m_video_duration        = MP4GetTrackDuration(m_hMP4File, m_video_trId);

        // Number of video samples, video frame rate
        m_video_num_samples     = MP4GetTrackNumberOfSamples(m_hMP4File, m_video_trId);
        m_video_framerate       = MP4GetTrackVideoFrameRate(m_hMP4File, m_video_trId);
        m_video_sample_max_size = MP4GetTrackMaxSampleSize(m_hMP4File, m_video_trId);

        GetVideoProfileAndSize(m_hMP4File, m_video_trId, m_video_codec,
                               &m_video_profile, &m_video_width, &m_video_height);

printf("/n m_video_framerate = (%f) !! m_video_duration = (%d), m_video_timescale = (%d)/n", m_video_framerate, m_video_duration, m_video_timescale);
    }
//这里因为头文件里面的音视频信息并不是准确的,经常会出错
//因而这里我们写了一个函数来专门确定我们的媒体属性
//GetVideoProfileAndSize
//视频的完了就取音频

    /////////////////////////////////////////////////////////
    /////                                               /////
    /////  3. Identify the audio & get its properties.  /////
    /////                                               /////
    /////////////////////////////////////////////////////////
    m_audio_trId = MP4FindTrackId(m_hMP4File, 0, MP4_AUDIO_TRACK_TYPE, 0);
    if (m_audio_trId != MP4_INVALID_TRACK_ID) {
        audio_name = (char *) MP4GetTrackMediaDataName(m_hMP4File, m_audio_trId);
        if (strcmp(audio_name, "mp4a") == 0)
            m_audio_codec = RAW_STRM_TYPE_M4A;            // MPEG4 AAC
        else if (strcmp(audio_name, "samr") == 0)
            m_audio_codec = RAW_STRM_TYPE_AMR_NB;        // AMR-NB
        else {
            printf("/n !! Unknown Audio (%s) !!/n", audio_name);
            m_audio_codec = 4;    // Unknown
        }

        // Timescale (ticks per second) and duration of the Video track
        m_audio_timescale       = MP4GetTrackTimeScale(m_hMP4File, m_audio_trId);
        m_audio_duration        = MP4GetTrackDuration(m_hMP4File, m_audio_trId);

        // Number of video samples, video width, video height, video frame rate
        m_audio_num_samples     = MP4GetTrackNumberOfSamples(m_hMP4File, m_audio_trId);
        m_audio_num_channels    = 2;//MP4GetTrackAudioChannels(m_hMP4File, m_audio_trId);
        m_audio_sample_max_size = MP4GetTrackMaxSampleSize(m_hMP4File, m_audio_trId);

printf("/n m_audio_trId = %d, m_audio_duration = (%d), m_audio_timescale = (%d) !!/n", m_audio_trId, m_audio_duration, m_audio_timescale);
    }
//最后函数返回
    return S_OK;
}

我们看看GetVideoProfileAndSize是怎么写的,其实实现起来也不是很难。
static int GetVideoProfileAndSize(MP4FileHandle mp4File, MP4TrackId video_trId, int video_codec,
                                  int  *profile, int *width, int *height)
{
    int             b, ret;

    unsigned char   strm_hdr_buf[512];
    int             strm_hdr_leng;
    u_int8_t       *p_video_sample=NULL;
    u_int32_t       n_video_sample=0;


    if (RAW_STRM_TYPE_H263 == video_codec) {
//如果是H263,我们就直接读一帧再说,然后分析帧就可以得到正确的信息
        b = MP4ReadSample(mp4File, video_trId, 1/*sample_id=1*/,
                          &p_video_sample, &n_video_sample,
                          NULL, NULL, NULL, NULL);

        ret = get_h263_info(p_video_sample, n_video_sample, profile, width, height);
        free(p_video_sample);
        RETAILMSG(1, (L"[SSAP MP4Parser] Vedio Type:H263/n"));
    }
    else if (RAW_STRM_TYPE_M4V == video_codec) {
        strm_hdr_leng = sizeof(strm_hdr_buf);
        ret = GetVideoStreamHeader(mp4File, video_trId, video_codec,
                                   strm_hdr_buf, &strm_hdr_leng);

        // Profile and size information are directly obtained from the video stream header.
        ret = get_mpeg4_info(strm_hdr_buf, strm_hdr_leng, profile, width, height);
        RETAILMSG(1, (L"[SSAP MP4Parser] Vedio Type:M4V/n"));
    }
    else if (RAW_STRM_TYPE_H264RAW == video_codec) {
        strm_hdr_leng = sizeof(strm_hdr_buf);
        ret = GetVideoStreamHeader(mp4File, video_trId, video_codec,
                                   strm_hdr_buf, &strm_hdr_leng);
        // Profile and size information are directly obtained from the video stream header.
        ret = get_h264_info(strm_hdr_buf, strm_hdr_leng, profile, width, height);
        RETAILMSG(1, (L"[SSAP MP4Parser] Vedio Type:H263RAW/n"));
    }


    return 0;
}
这里又涉及到另外两个函数:
static int GetAudioStreamHeader(MP4FileHandle mp4File, MP4TrackId audio_trId, int audio_codec,
                                unsigned char *strm_hdr_buf, int *strm_hdr_leng)
{
    int            b;

    // for MPEG4
    u_int32_t      n_audio_conf;
    u_int8_t      *p_audio_conf;

    // for AMR-NB
    u_int16_t      amr_mode_set;


    switch (audio_codec) {
    case RAW_STRM_TYPE_M4A:
        p_audio_conf = NULL;
        n_audio_conf = 0;
        b = MP4GetTrackESConfiguration(mp4File, audio_trId, &p_audio_conf, &n_audio_conf);
        if (!b)
            return -1;
        memcpy(strm_hdr_buf, p_audio_conf, n_audio_conf);
        *strm_hdr_leng = n_audio_conf;
        free(p_audio_conf);
        RETAILMSG(1, (L"[SSAP MP4Parser] Audio Type:M4A/n"));
        break;

    case RAW_STRM_TYPE_AMR_NB:
        amr_mode_set = MP4GetAmrModeSet(mp4File, audio_trId);
        strm_hdr_buf[0] = (unsigned char) amr_mode_set;
        strm_hdr_buf[1] = (unsigned char) (amr_mode_set >> 8);
        *strm_hdr_leng = 2;
        RETAILMSG(1, (L"[SSAP MP4Parser] Audio Type:AMR_NB/n"));
        break;

    default:
        RETAILMSG(1, (L"[SSAP MP4Parser]unsupported file type/n"));
        return E_FAIL;
    }


    return 0;
}

static int GetVideoStreamHeader(MP4FileHandle mp4File, MP4TrackId video_trId, int video_codec,
                                unsigned char *strm_hdr_buf, int *strm_hdr_leng)
{
    int            b;

    // for MPEG4
    u_int8_t      *p_video_conf;
    u_int32_t      n_video_conf;

    // for H.264
    u_int8_t     **pp_sps, **pp_pps;
    u_int32_t     *pn_sps, *pn_pps;
    u_int32_t      n_strm_size;
    int            i;


    switch (video_codec) {
    case RAW_STRM_TYPE_M4V:        // MPEG4
        p_video_conf = NULL;
        n_video_conf = 0;
        b = MP4GetTrackESConfiguration(mp4File, video_trId,
                                       &p_video_conf, &n_video_conf);
        if (!b)
            return -1;

        memcpy(strm_hdr_buf, p_video_conf, n_video_conf);
        free(p_video_conf);

        *strm_hdr_leng = n_video_conf;
        break;

    case RAW_STRM_TYPE_H263:        // H.263
        *strm_hdr_leng = 0;
        break;

    case RAW_STRM_TYPE_H264RAW:        // H.264
        pp_sps = pp_pps = NULL;
        pn_sps = pn_pps = NULL;
        n_strm_size     = 0;

        b = MP4GetTrackH264SeqPictHeaders(mp4File, video_trId, &pp_sps, &pn_sps, &pp_pps, &pn_pps);
        if (!b)
            return -1;

        // SPS memcpy
        if (pp_sps) {
            for (i=0; *(pp_sps + i); i++) {
                memcpy(strm_hdr_buf + n_strm_size, h264_delimiter, sizeof(h264_delimiter));
                n_strm_size += sizeof(h264_delimiter);
                memcpy(strm_hdr_buf + n_strm_size, *(pp_sps + i), *(pn_sps + i));
/*
                if (NAL_UNIT_TYPE_TYPE(strm_hdr_buf[n_strm_size]) == 7) {
                    strm_hdr_buf[n_strm_size + 1] = 66;
                }
*/
                n_strm_size += *(pn_sps + i);
                free(*(pp_sps + i));
            }
            free(pp_sps);
        }
        // PPS memcpy
        if (pp_pps) {
            for (i=0; *(pp_pps + i); i++) {
                memcpy(strm_hdr_buf + n_strm_size, h264_delimiter, sizeof(h264_delimiter));
                n_strm_size += sizeof(h264_delimiter);
                memcpy(strm_hdr_buf + n_strm_size, *(pp_pps + i), *(pn_pps + i));
                n_strm_size += *(pn_pps + i);

                free(*(pp_pps + i));
            }
            free(pp_pps);
        }

        *strm_hdr_leng = n_strm_size;
        break;

    default:    // Unknown
        *strm_hdr_leng = 0;
        break;
    }

    return 0;
}
有兴趣的可以看一下,然后我们的工作基本上可以说是已经完成,我所说的是filter的工作已经完 成,这里因为媒体类型都在这,我们又实现了两个函数,因为我们的outpin是要传输数据的,那我们的数据怎么去取,取什么地方的数据,总要有一个函数和 标识。这里,为了后面的取数据方便,我们分别定义了音频和视频的读取函数:

这里我们读取数据都是有一个sample_id,文件储存是按照一帧一帧的存储的,得到sample_id,就可以得到该帧的文件偏移,然后读取文件到buff
int CMP4ParserFilter::GetAudioFrame(unsigned char *pFrameBuf, unsigned int *pSize, int sample_id)
{
    int nRead;

    u_int8_t      *p_audio_sample;
    u_int32_t      n_audio_sample;

    int            b, ret;


    p_audio_sample = (u_int8_t *) pFrameBuf;
    n_audio_sample = *pSize;


    if ((sample_id <= 0) || (sample_id > m_audio_num_samples)) {
        RETAILMSG(1, (L"/n[CMP4ParserFilter::GetAudioFrame] /'sample_id/' is invalid. (sample_id = %d", sample_id));
        *pSize = 0;
        return -1;
    }

    /////////////////////
    //  MP4ReadSample  //
    /////////////////////
    b = MP4ReadSample(m_hMP4File, m_audio_trId, sample_id,
                      &p_audio_sample, &n_audio_sample,
                      NULL, NULL, NULL, NULL);
    if (!b) {
        *pSize = 0;
        return -1;
    }

//printf("/n  --- MP4ReadSample=%d", n_audio_sample);

    *pSize = nRead = n_audio_sample;

    return nRead;
}

int CMP4ParserFilter::GetVideoFrame(unsigned char *pFrameBuf, unsigned int *pSize, unsigned int *isIframe, int sample_id)
{
    int nRead;

    int            n_video_hdr;

    u_int8_t      *p_video_sample;
    u_int32_t      n_video_sample;

    int            b, ret;


    p_video_sample = (u_int8_t *) pFrameBuf;
    n_video_sample = *pSize;


    if ((sample_id <= 0) || (sample_id > m_video_num_samples)) {
        RETAILMSG(1, (L"/n[CMP4ParserFilter::GetVideoFrame] /'sample_id/' is invalid. (sample_id = %d", sample_id));
        *pSize = 0;
        return -1;
    }

    // if (sampleId == 1),
    // then "video stream header" is extracted and it is put in the buffer.
    if (sample_id == 1) {
        ret = GetVideoStreamHeader(m_hMP4File, m_video_trId, m_video_codec,
                                   pFrameBuf, &n_video_hdr);

        p_video_sample += n_video_hdr;
        n_video_sample -= n_video_hdr;
    }
    else
        n_video_hdr = 0;

    /////////////////////
    //  MP4ReadSample  //
    /////////////////////
    b = MP4ReadSample(m_hMP4File, m_video_trId, sample_id,
                      &p_video_sample, &n_video_sample,
                      NULL, NULL, NULL, NULL);
    if (!b) {
        *pSize = 0;
        return -1;
    }

    // if (codec == h.264), the first 4 bytes are the length octets.
    // They need to be changed to H.264 delimiter (00 00 00 01).
    if (m_video_codec == RAW_STRM_TYPE_H264RAW) {
        int h264_nal_leng;
        int nal_leng_acc = 0;
        do {
            h264_nal_leng = p_video_sample[0];
            h264_nal_leng = (h264_nal_leng << 8) | p_video_sample[1];
            h264_nal_leng = (h264_nal_leng << 8) | p_video_sample[2];
            h264_nal_leng = (h264_nal_leng << 8) | p_video_sample[3];
            memcpy(p_video_sample, h264_delimiter, 4);
            nal_leng_acc   += (h264_nal_leng + 4);
            p_video_sample += (h264_nal_leng + 4);
        } while (nal_leng_acc < n_video_sample);
    }


    *pSize = nRead = (n_video_hdr + n_video_sample);
    *isIframe  = MP4GetSampleSync(m_hMP4File, m_video_trId, sample_id);


    return nRead;
}

这样Source filter的FIlter部分算基本完成了,其实思路都很清晰的。
在后面我们来慢慢讲outputpin的实现。

(vblittleboy)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201109/15012.html]
本文出处:blog.csdn.net/vblittleboy 作者:vblittleboy
顶一下
(1)
20%
踩一下
(4)
80%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容