使用libavcodec编码direcshow帧缓冲区

时间:2013-01-06 10:28:40

标签: visual-c++ directshow libavcodec

我正在尝试使用libavcodec编码由ISampleGrabber(directshow)抓取的帧的流缓冲区。编码这些帧后,我将其写入文件。但完成后文件只包含绿色框架。

她是抓取帧并对其进行编码的代码......

void DSGrabberCallback::initFFMpeg(){
    const char* filename="G:/test1.mpg";
    avcodec_register_all();
    printf("Encode video file %s\n", filename);

    AVCodecID codec_id=AV_CODEC_ID_MPEG2VIDEO;
    codec = avcodec_find_encoder(codec_id);

    c = avcodec_alloc_context3(codec);

    if (!c) {
        fprintf(stderr, "Could not allocate video codec context\n");
    }

    c->bit_rate = 4000000;
    c->width = 320;
    c->height = 240;

    AVRational test;
    test.den=25;
    test.num=1;
    c->time_base= test;
    c->gop_size = 10;
    //c->max_b_frames=1;
    c->pix_fmt = AV_PIX_FMT_YUV420P;

    if(codec_id == AV_CODEC_ID_H264)
        av_opt_set(c->priv_data, "preset", "slow", 0);

    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
    }

    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
    }

    picture = alloc_picture(c->pix_fmt, c->width, c->height);


    /*picture->format = c->pix_fmt;
    picture->width  = c->width;
    picture->height = c->height;*/

    av_init_packet(&pkt);

}

void DSGrabberCallback::encodeFrame(unsigned char *frame,ULONG size){

    std::cout<<"called.....";

    pkt.data = NULL;   
    pkt.size = 0; 
    picture->data[0]=frame;
    fflush(stdout);

    picture->pts=counter;


    ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
    if (ret < 0) {
        fprintf(stderr, "Error encoding frame\n");
    }

    if (got_output) {
        printf("Write frame %3d (size=%5d)\n", counter, pkt.size);
        fwrite(pkt.data, 1, pkt.size, f);
        av_free_packet(&pkt);
    }
}

STDMETHODIMP DSGrabberCallback::SampleCB(double time, IMediaSample* sample)
{
    BYTE* data = NULL;
    ULONG length = 0;
    m_bytes=NULL;

    counter=counter+1;

    if(FAILED(sample->GetPointer(&data)))
    {
        return E_FAIL;
    }

    length = sample->GetActualDataLength();
    if(length == 0)
    {
        return S_OK;
    }

    if(!m_bytes || m_bytesLength < length)
    {
        if(m_bytes)
        {
            delete[] m_bytes;
        }

        m_bytes = new unsigned char[length];
        m_bytesLength = length;
    }
    if(true)
    {
        for(size_t row = 0 ; row < 480 ; row++)
        {
            memcpy((m_bytes + row * 640 * 2), data + (480 - 1 - row) * 640 * 2,
                640 * 2);
        }
    }
    std::cout<<"hiiiiiiiiiiiiiiiiiiiiiiii";

    // memcpy(m_bytes, data, length);
    // std::cout<<"called............... "<<m_bytes<<"\n";
    if(counter<500){
        encodeFrame(m_bytes,length);
    }else{
        fwrite(endcode, 1, sizeof(endcode), f);
        fclose(f);
        avcodec_close(c);
        av_free(c);
        av_freep(&picture->data[0]);
        avcodec_free_frame(&picture);
        printf("\n");
        exit(1);
    }


    //rtp.sendRTP(data,length);

    //sample->Release();
    //printf("Sample received: %p %u\n", data, length);


    return S_OK;
}

谁能告诉我问题出在哪里。

1 个答案:

答案 0 :(得分:0)

现在工作正常。实际上我忘记将图像缓冲区转换为YUV420P格式。我已经添加了一些代码来将缓冲区缩放为YUV格式,现在一切都很好。谢谢Wimmel和Roman R.