首页 新闻 搜索 专区 学院

ffmpeg 解码h264数据丢帧

0
悬赏园豆:100 [待解决问题]

 开发环境Arm+Ubuntu14.04。

 应用环境是 一帧帧的h264数据(顺序的20帧的h264数据,文件名分别是1.h264,2.h264,3.h264, ...... 20.h264且只有I帧 和P帧,无B帧,分辨率1920*1080),要求使用FFmpeg 相关api 编写测试程序解析h264数据,输出yuv文件。

说明本版本的  FFmpeg库 在调用解码avformat_open_input()av_find_stream_info()打开单帧的h264文件的时候报错如下:

ERROR:RkCodecInit:1221 video width(0) * height(0) is invalid
after init
[h264_rkvpu @ 0x13a10] [IMGUTILS @ 0xbeac3f2c] Picture size 0x0 is invalid
[h264_rkvpu @ 0x13a10] video_get_buffer: image parameters invalid
[h264_rkvpu @ 0x13a10] get_buffer() failed
[h264_rkvpu @ 0x13a10] Failed to get buffer!!!:-22Something wrong during decode!!!Picture size 0x0 is invalid
[h264_rkvpu @ 0x13a10] video_get_buffer: image parameters invalid
[h264_rkvpu @ 0x13a10] get_buffer() failed
[h264_rkvpu @ 0x13a10] Failed to get buffer!!!:-22Something wrong during decode!!!Picture size 0x0 is invalid
[[h264_rkvpu @ 0x13a10] Failed to get buffer!!!:-22Something wrong during decode!!!decoding for stream 0 failed
[h264 @ 0x13020] Could not find codec parameters for stream 0 (Video: h264, yuv420p): unspecified size
Consider increasing the value for the 'analyzeduration' and 'probesize' options

最终要求的是当前的开发环境,用不了avformat_open_input()av_find_stream_info()av_read_frame()等函数。

再次致敬雷霄骅博士,参考他的程序,本人程序如下:但是用此程序解码文件问题是解码程序总会丢一帧

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <libavformat/avformat.h>
#include  <libavcodec/avcodec.h>
#include <libswscale/swscale.h>

int main(int argc, char* argv[])
{
    AVCodec *pCodec;
    AVCodecContext *pCodecCtx= NULL;
    AVCodecParserContext *pCodecParserCtx=NULL;

    int frame_count,i;
    FILE *fp_in;
    FILE *fp_out;
    AVFrame    *pFrame,*pFrameYUV;
    uint8_t *out_buffer;
    const int in_buffer_size=300000;
    uint8_t  in_buffer[300000+32]={0};
    uint8_t *cur_ptr;
    int cur_size;

    AVPacket packet;
    int ret, got_picture;

    int y_size;
    enum AVCodecID codec_id;

    codec_id=AV_CODEC_ID_H264;
    
    char filepath_out[]="test.yuv";
    int first_time=1;
    int m_skippedframe=0;
    int    DecFrameNum=0;
    int filesize =0;
    struct SwsContext *img_convert_ctx;

    avcodec_register_all();
    pCodec = avcodec_find_decoder(codec_id);
    if (!pCodec) 
    {
        printf("Codec not found\n");
        return -1;
    }
    pCodecCtx = avcodec_alloc_context3(pCodec);
    if (!pCodecCtx)
    {
        printf("Could not allocate video codec context\n");
        return -1;
    }

    /*必须设置,否则程序解码会报error*/
    pCodecCtx->width =1920 ;
      pCodecCtx->height=1080;

    pCodecParserCtx=av_parser_init(codec_id);
    if (!pCodecParserCtx)
    {
        printf("Could not allocate video parser context\n");
        return -1;
    }

    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("Could not open codec\n");
        return -1;
    }

    //Output File
    fp_out = fopen(filepath_out, "wb");
    if (!fp_out) 
    {
        printf("Could not open output YUV file\n");
        return -1;
    }
        
    //Input File
    char filename_body[10];
       for(i =1;i<=20;i++)
    {
        char filename[20] ={0};
        memset(filename_body,0,sizeof(filename_body));
        sprintf(filename_body,"%d",i);
        strcat(filename,filename_body);
        char filename_tail[5] = ".h264";
        strcat(filename,filename_tail);

        printf("filename =%s\n",filename);
        
        fp_in = fopen(filename, "rb");
        if (!fp_in) 
        {
            printf("Could not open input stream\n");
            return -1;
          }
         fseek(fp_in, 0L, SEEK_END);
         filesize=ftell(pInFile);
        
            pFrame = av_frame_alloc();
        av_init_packet(&packet);

        while (1) 
        {
            cur_size = fread(in_buffer, 1, in_buffer_size, fp_in);
            printf("cur_size =%d\n",cur_size);
            if (cur_size == 0)
                break;
            cur_ptr=in_buffer;

            while (cur_size>0)
            {
            
                int len = av_parser_parse2(
                pCodecParserCtx, pCodecCtx,
                &packet.data, &packet.size,
                cur_ptr , cur_size ,
                AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);

                cur_ptr += len;
                cur_size -= len;
                if(packet.size==0)
                    continue;

                //Some Info from AVCodecParserContext
                printf("Packet Size:%6d\t",packet.size);
                switch(pCodecParserCtx->pict_type)
                {
                    case AV_PICTURE_TYPE_I: printf("Type: I\t");break;
                    case AV_PICTURE_TYPE_P: printf("Type: P\t");break;
                    case AV_PICTURE_TYPE_B: printf("Type: B\t");break;
                        default: printf("Type: Other\t");break;
                }
                printf("Output Number:%4d\t",pCodecParserCtx->output_picture_number);
                printf("Offset:%lld\n",pCodecParserCtx->cur_offset);

                

                ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);
                if (ret < 0) 
                {
                    printf("Decode Error.\n");
                    return ret;
                }
                if (got_picture) 
                {
                    if(first_time)
                    {
                        printf("\nCodec Full Name:%s\n",pCodecCtx->codec->long_name);
                        printf("width:%d\nheight:%d\n\n",pCodecCtx->width,pCodecCtx->height);
                        //SwsContext
                        img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 
                            pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); 
                        
                        pFrameYUV=av_frame_alloc();
                        out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
                        avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
                        
                        y_size=pCodecCtx->width*pCodecCtx->height;

                        first_time=0;
                    }
                    DecFrameNum++;
                    printf("Succeed to decode 1 frame!,DecFrameNum =%d\n",DecFrameNum);
                    sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, 
                        pFrameYUV->data, pFrameYUV->linesize);

                    fwrite(pFrameYUV->data[0],1,y_size,fp_out);     //Y 
                    fwrite(pFrameYUV->data[1],1,y_size/4,fp_out);   //U
                    fwrite(pFrameYUV->data[2],1,y_size/4,fp_out);   //V
                    usleep(40*1000);
                    
            }
        else
            {
                m_skippedframe++;
                printf("\n ******m_skippedframe =%d\n",m_skippedframe);
            }    
                    av_free_packet(&packet);
        }

    }
    }

        //Flush Decoder
        while(1)
        {
            printf("8888\n");
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);
            printf("flush got_picture =%d\n",got_picture);
            if (ret < 0) 
            {
                printf("Decode Error.\n");
                return ret;
            }
            if (!got_picture)
                break;
            if (got_picture) 
            {
                printf("Flush Decoder: Succeed to decode 1 frame!\n");
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, 
                    pFrameYUV->data, pFrameYUV->linesize);

                fwrite(pFrameYUV->data[0],1,y_size,fp_out);     //Y
                fwrite(pFrameYUV->data[1],1,y_size/4,fp_out);   //U
                fwrite(pFrameYUV->data[2],1,y_size/4,fp_out);   //V
            }
            av_free_packet(&packet);
        }

    printf("99999\n");
        fclose(fp_in);
    fclose(fp_out);
    
    sws_freeContext(img_convert_ctx);
    av_parser_close(pCodecParserCtx);

    av_frame_free(&pFrameYUV);
    av_frame_free(&pFrame);
    avcodec_close(pCodecCtx);
    av_free(pCodecCtx);

    return 0;
}
复制代码

 

   

恳请诸位高手帮忙分析问题

问题补充:

附上:执行log
root@ubuntu:# ./test
after init
filename =1.h264
cur_size =259391
cur_size =0
filename =2.h264
cur_size =104236
Packet Size:259391 Type: I Output Number: 0 Offset:-9223372036854516417

******m_skippedframe =1
cur_size =0
filename =3.h264
cur_size =68139
Packet Size:104236 Type: P Output Number: 2 Offset:-9223372036854412181

Codec Full Name:h264_rkvpu hw decoder
width:1920
height:1080

Succeed to decode 1 frame!,DecFrameNum =1
cur_size =0
filename =4.h264
cur_size =46712
Packet Size: 68139 Type: P Output Number: 4 Offset:-9223372036854344042

******m_skippedframe =2
cur_size =0
filename =5.h264
cur_size =129677
Packet Size: 46712 Type: P Output Number: 6 Offset:-9223372036854297330
Succeed to decode 1 frame!,DecFrameNum =2
cur_size =0
filename =6.h264
cur_size =50414
Packet Size:129677 Type: I Output Number: 0 Offset:-9223372036854167653
Succeed to decode 1 frame!,DecFrameNum =3
cur_size =0
filename =7.h264
cur_size =52537
Packet Size: 50414 Type: P Output Number: 2 Offset:-9223372036854117239
Succeed to decode 1 frame!,DecFrameNum =4
cur_size =0
filename =8.h264
cur_size =52254
Packet Size: 52537 Type: P Output Number: 4 Offset:-9223372036854064702
Succeed to decode 1 frame!,DecFrameNum =5
cur_size =0
filename =9.h264
cur_size =4793
Packet Size: 52254 Type: P Output Number: 6 Offset:-9223372036854012448
Succeed to decode 1 frame!,DecFrameNum =6
cur_size =0
filename =10.h264
cur_size =127786
Packet Size: 4793 Type: P Output Number: 8 Offset:-9223372036854007655
Succeed to decode 1 frame!,DecFrameNum =7
cur_size =0
filename =11.h264
cur_size =59473
Packet Size:127786 Type: I Output Number: 0 Offset:-9223372036853879869
Succeed to decode 1 frame!,DecFrameNum =8
cur_size =0
filename =12.h264
cur_size =48709
Packet Size: 59473 Type: P Output Number: 2 Offset:-9223372036853820396
Succeed to decode 1 frame!,DecFrameNum =9
cur_size =0
filename =13.h264
cur_size =45737
Packet Size: 48709 Type: P Output Number: 4 Offset:-9223372036853771687
Succeed to decode 1 frame!,DecFrameNum =10
cur_size =0
filename =14.h264
cur_size =45510
Packet Size: 45737 Type: P Output Number: 6 Offset:-9223372036853725950
Succeed to decode 1 frame!,DecFrameNum =11
cur_size =0
filename =15.h264
cur_size =126716
Packet Size: 45510 Type: P Output Number: 8 Offset:-9223372036853680440
Succeed to decode 1 frame!,DecFrameNum =12
cur_size =0
filename =16.h264
cur_size =45331
Packet Size:126716 Type: I Output Number: 0 Offset:-9223372036853553724
Succeed to decode 1 frame!,DecFrameNum =13
cur_size =0
filename =17.h264
cur_size =46676
Packet Size: 45331 Type: P Output Number: 2 Offset:-9223372036853508393
Succeed to decode 1 frame!,DecFrameNum =14
cur_size =0
filename =18.h264
cur_size =45808
Packet Size: 46676 Type: P Output Number: 4 Offset:-9223372036853461717
Succeed to decode 1 frame!,DecFrameNum =15
cur_size =0
filename =19.h264
cur_size =48620
Packet Size: 45808 Type: P Output Number: 6 Offset:-9223372036853415909
Succeed to decode 1 frame!,DecFrameNum =16
cur_size =0
filename =20.h264
cur_size =103297
Packet Size: 48620 Type: P Output Number: 8 Offset:-9223372036853367289
Succeed to decode 1 frame!,DecFrameNum =17
cur_size =0
8888
flush got_picture =1
Flush Decoder: Succeed to decode 1 frame!
8888
flush got_picture =1
Flush Decoder: Succeed to decode 1 frame!
8888
flush got_picture =0
99999


shuimu999的主页 shuimu999 | 初学一级 | 园豆:102
提问于:2017-02-21 16:20
< >
分享
所有回答(3)
0

拿走100分 ,可能会送命。


长蘑菇星人 | 园豆:1832 (小虾三级) | 2017-02-21 16:22

不好意思,不太熟悉发帖,刚才代码格式太乱


支持(0) 反对(0) shuimu999 | 园豆:102 (初学一级) | 2017-02-21 16:47
0

那个库没问题。

日暮青色 | 园豆:455 (菜鸟二级) | 2017-02-22 08:59

恩,我描述有问题,解码库只是用不了avformat_open_input()av_find_stream_info()av_read_frame()等函数,不会影响丢帧。丢帧是这个测试程序问题,但是不知道如何改进


支持(0) 反对(0) shuimu999 | 园豆:102 (初学一级) | 2017-02-22 09:28
0

如果1.h264等每个文件是一帧,没有其它元数据。不需要avformat_open_input()av_find_stream_info()av_read_frame()等函数,直接完整读取文件,构造一个AVFrame进行解码就行了。

 

alby | 园豆:323 (菜鸟二级) | 2017-02-22 09:41

多谢回复,1.h264,就是一帧,没其他数据,也试过读取一帧的文件直接丢到packet,然后解码,也是丢最后一帧
fseek(fp_in, 0L, SEEK_END);
filesize=ftell(fp_in);
fseek(fp_in, 0L, SEEK_SET);

        pFrame = av_frame_alloc();
    av_init_packet(&packet);

    while (1) 
    {
        cur_size = fread(in_buffer, 1, /*in_buffer_size*/filesize, fp_in);
        printf("cur_size =%d\n",cur_size);
        if (cur_size == 0)
            break;
        //cur_ptr=in_buffer;
        packet.data=in_buffer;
        packet.size =filesize;
          ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);

.......


支持(0) 反对(0) shuimu999 | 园豆:102 (初学一级) | 2017-02-22 10:10
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册