视频编解码学习(2):H264学习笔记

时间:2022-02-17 17:11:36

RT


文章1:最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)

http://blog.csdn.net/leixiaohua1020/article/details/38868499

文章2:最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)

http://blog.csdn.net/leixiaohua1020/article/details/42181571


现在把我学习的重要内容总结一下:


在文章1里面,有一段代码:

int iFrameIndex = 1;
    while( av_read_frame(pFormatCtx, packet) >= 0 ) {
        m_mylog.LogFile(_T("Frame: %d, Size: %d"), iFrameIndex ++, packet->size);
        
        if( packet->stream_index == videoindex ) {
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
            if( ret < 0 ) {
                printf("Decode Error.\n");
                return -1;
            }
        }
    }
这里会计算该文件有多少个Frame,我测试的结果为250,但这里仅贴出前10个Frame的结果。

DEBUG - Frame: 1, Size: 22572
DEBUG - Frame: 2, Size: 2803
DEBUG - Frame: 3, Size: 623
DEBUG - Frame: 4, Size: 495
DEBUG - Frame: 5, Size: 3730
DEBUG - Frame: 6, Size: 699
DEBUG - Frame: 7, Size: 635
DEBUG - Frame: 8, Size: 4056
DEBUG - Frame: 9, Size: 552
DEBUG - Frame: 10, Size: 613


同理在文章2里面,有一段代码:

    while( 1 ) {
        // 
        cur_size = fread(in_buffer, 1, IN_BUFFER_SIZE, fp_in);
        if( cur_size == 0 ) {
            break;
        }
        cur_ptr = in_buffer;
        
        while( cur_size > 0 ) {
            // 解析获得一个Packet
            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;
            }
            
            // decode this buffer
            //Some Info from AVCodecParserContext
            m_mylog.LogFile(_T("Index: %d Packet Size:%6d"), iPacketIndex ++, packet.size);

            // ...
        }
也是获取有多少个Frame的,不过使用的方法不一样。但是结果是相同的。


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 2015/7/22今天我好好的调试了一个h264文件,想要探索它究竟是什么?当然了,不可避免的需要学习新知识。

先给出几个自问自答。

1. h264是什么?

新一代高清视频编码格式

2. NALU是什么?

答:NALU头结构:NALU类型(5bit)、重要性指示位(2bit)、禁止位(1bit)

因为NALU在文件里面是二进制的,为了区分这些NALU,需要定义(0x00000001或者0x000001)来作为间隔符。

区别:如果NALU对应的Slice(Slice为P帧,也就是差别帧)为一帧的开始,则用4字节表示,即0x00000001;否则用3字节表示,0x000001。


参考:http://blog.csdn.net/wudebao5220150/article/details/13810671


3.如何解析h264 ?

为了解析h264,我先上传一个 h264的文件ds.h264

该文件大小为:201,432 字节

3.1 使用ffmpeg解析h264文件

参考:http://blog.csdn.net/leixiaohua1020/article/details/38868499

首先使用FFMPEG里面的av_read_frame读取所有的帧,得到如下结果:
Frame: 1, Size: 9777
Frame: 2, Size: 215
Frame: 3, Size: 113
Frame: 4, Size: 75
Frame: 5, Size: 95
Frame: 6, Size: 435
Frame: 7, Size: 217
Frame: 8, Size: 123
Frame: 9, Size: 139
Frame: 10, Size: 913
Frame: 11, Size: 291
Frame: 12, Size: 182
Frame: 13, Size: 184
Frame: 14, Size: 10118
Frame: 15, Size: 1017
Frame: 16, Size: 260
Frame: 17, Size: 235
Frame: 18, Size: 2773
Frame: 19, Size: 509
Frame: 20, Size: 340
Frame: 21, Size: 361
Frame: 22, Size: 5374
Frame: 23, Size: 841
Frame: 24, Size: 608
Frame: 25, Size: 363
Frame: 26, Size: 5233
Frame: 27, Size: 1143
Frame: 28, Size: 677
Frame: 29, Size: 486
Frame: 30, Size: 4918
Frame: 31, Size: 1330
Frame: 32, Size: 659
Frame: 33, Size: 591
Frame: 34, Size: 4944
Frame: 35, Size: 1745
Frame: 36, Size: 777
Frame: 37, Size: 923
Frame: 38, Size: 5555
Frame: 39, Size: 1930
Frame: 40, Size: 1037
Frame: 41, Size: 1093
Frame: 42, Size: 5735
Frame: 43, Size: 2351
Frame: 44, Size: 1296
Frame: 45, Size: 1246
Frame: 46, Size: 5268
Frame: 47, Size: 2193
Frame: 48, Size: 1142
Frame: 49, Size: 1006
Frame: 50, Size: 4657
Frame: 51, Size: 2039
Frame: 52, Size: 919
Frame: 53, Size: 950
Frame: 54, Size: 5293
Frame: 55, Size: 2063
Frame: 56, Size: 799
Frame: 57, Size: 862
Frame: 58, Size: 5294
Frame: 59, Size: 1743
Frame: 60, Size: 1136
Frame: 61, Size: 890
Frame: 62, Size: 5284
Frame: 63, Size: 1902
Frame: 64, Size: 920
Frame: 65, Size: 962
Frame: 66, Size: 5593
Frame: 67, Size: 2280
Frame: 68, Size: 1087
Frame: 69, Size: 907
Frame: 70, Size: 5525
Frame: 71, Size: 2117
Frame: 72, Size: 976
Frame: 73, Size: 1202
Frame: 74, Size: 5578
Frame: 75, Size: 2170
Frame: 76, Size: 981
Frame: 77, Size: 951
Frame: 78, Size: 5468
Frame: 79, Size: 1555
Frame: 80, Size: 1009
Frame: 81, Size: 710
Frame: 82, Size: 5009
Frame: 83, Size: 1361
Frame: 84, Size: 691
Frame: 85, Size: 638
Frame: 86, Size: 4953
Frame: 87, Size: 1514
Frame: 88, Size: 607
Frame: 89, Size: 778
Frame: 90, Size: 4590
Frame: 91, Size: 1390
Frame: 92, Size: 607
Frame: 93, Size: 526
Frame: 94, Size: 4905
Frame: 95, Size: 1282
Frame: 96, Size: 651
Frame: 97, Size: 654
Frame: 98, Size: 5477
Frame: 99, Size: 2072
Frame: 100, Size: 1069

Total Frame Size: 201432
看到没有,正好是201432,这样一看,一共有100帧。但是还有其他问题,哪些是I帧,哪些是P帧?如何将这些帧通过RTP发送出去呢?这些帧在二进制的格式是什么?好,别急,现在只是FFMPEGE帮助我解析了这些帧,当然文件h264文件在手,我也可以自己解析这些帧。



3.2 全手工解析h264文件

参考:http://download.csdn.net/download/yechuanfei/4313339
将该文章里面的代码下载后,并仔细调试,我得到如下结果:
Index: 1 -- len: 24 	-- prefix: 4 	nal_unit_type: 7
Index: 2 -- len: 5 	-- prefix: 4 	nal_unit_type: 8
Index: 3 -- len: 698 	-- prefix: 3 	nal_unit_type: 6
Index: 4 -- len: 9036 	-- prefix: 3 	nal_unit_type: 5
Index: 5 -- len: 211 	-- prefix: 4 	nal_unit_type: 1
Index: 6 -- len: 109 	-- prefix: 4 	nal_unit_type: 1
Index: 7 -- len: 71 	-- prefix: 4 	nal_unit_type: 1
Index: 8 -- len: 91 	-- prefix: 4 	nal_unit_type: 1
Index: 9 -- len: 431 	-- prefix: 4 	nal_unit_type: 1
Index: 10 -- len: 213 	-- prefix: 4 	nal_unit_type: 1
Index: 11 -- len: 119 	-- prefix: 4 	nal_unit_type: 1
Index: 12 -- len: 135 	-- prefix: 4 	nal_unit_type: 1
Index: 13 -- len: 909 	-- prefix: 4 	nal_unit_type: 1
Index: 14 -- len: 287 	-- prefix: 4 	nal_unit_type: 1
Index: 15 -- len: 178 	-- prefix: 4 	nal_unit_type: 1
Index: 16 -- len: 180 	-- prefix: 4 	nal_unit_type: 1
Index: 17 -- len: 10114 -- prefix: 4 	nal_unit_type: 1
Index: 18 -- len: 1013 	-- prefix: 4 	nal_unit_type: 1
Index: 19 -- len: 256 	-- prefix: 4 	nal_unit_type: 1
Index: 20 -- len: 231 	-- prefix: 4 	nal_unit_type: 1
Index: 21 -- len: 2769 	-- prefix: 4 	nal_unit_type: 1
Index: 22 -- len: 505 	-- prefix: 4 	nal_unit_type: 1
Index: 23 -- len: 336 	-- prefix: 4 	nal_unit_type: 1
Index: 24 -- len: 357 	-- prefix: 4 	nal_unit_type: 1
Index: 25 -- len: 5370 	-- prefix: 4 	nal_unit_type: 1
Index: 26 -- len: 837 	-- prefix: 4 	nal_unit_type: 1
Index: 27 -- len: 604 	-- prefix: 4 	nal_unit_type: 1
Index: 28 -- len: 359 	-- prefix: 4 	nal_unit_type: 1
Index: 29 -- len: 5229 	-- prefix: 4 	nal_unit_type: 1
Index: 30 -- len: 1139 	-- prefix: 4 	nal_unit_type: 1
Index: 31 -- len: 673 	-- prefix: 4 	nal_unit_type: 1
Index: 32 -- len: 482 	-- prefix: 4 	nal_unit_type: 1
Index: 33 -- len: 4914 	-- prefix: 4 	nal_unit_type: 1
Index: 34 -- len: 1326 	-- prefix: 4 	nal_unit_type: 1
Index: 35 -- len: 655 	-- prefix: 4 	nal_unit_type: 1
Index: 36 -- len: 587 	-- prefix: 4 	nal_unit_type: 1
Index: 37 -- len: 4940 	-- prefix: 4 	nal_unit_type: 1
Index: 38 -- len: 1741 	-- prefix: 4 	nal_unit_type: 1
Index: 39 -- len: 773 	-- prefix: 4 	nal_unit_type: 1
Index: 40 -- len: 919 	-- prefix: 4 	nal_unit_type: 1
Index: 41 -- len: 5551 	-- prefix: 4 	nal_unit_type: 1
Index: 42 -- len: 1926 	-- prefix: 4 	nal_unit_type: 1
Index: 43 -- len: 1033 	-- prefix: 4 	nal_unit_type: 1
Index: 44 -- len: 1089 	-- prefix: 4 	nal_unit_type: 1
Index: 45 -- len: 5731 	-- prefix: 4 	nal_unit_type: 1
Index: 46 -- len: 2347 	-- prefix: 4 	nal_unit_type: 1
Index: 47 -- len: 1292 	-- prefix: 4 	nal_unit_type: 1
Index: 48 -- len: 1242 	-- prefix: 4 	nal_unit_type: 1
Index: 49 -- len: 5264 	-- prefix: 4 	nal_unit_type: 1
Index: 50 -- len: 2189 	-- prefix: 4 	nal_unit_type: 1
Index: 51 -- len: 1138 	-- prefix: 4 	nal_unit_type: 1
Index: 52 -- len: 1002 	-- prefix: 4 	nal_unit_type: 1
Index: 53 -- len: 4653 	-- prefix: 4 	nal_unit_type: 1
Index: 54 -- len: 2035 	-- prefix: 4 	nal_unit_type: 1
Index: 55 -- len: 915 	-- prefix: 4 	nal_unit_type: 1
Index: 56 -- len: 946 	-- prefix: 4 	nal_unit_type: 1
Index: 57 -- len: 5289 	-- prefix: 4 	nal_unit_type: 1
Index: 58 -- len: 2059 	-- prefix: 4 	nal_unit_type: 1
Index: 59 -- len: 795 	-- prefix: 4 	nal_unit_type: 1
Index: 60 -- len: 858 	-- prefix: 4 	nal_unit_type: 1
Index: 61 -- len: 5290 	-- prefix: 4 	nal_unit_type: 1
Index: 62 -- len: 1739 	-- prefix: 4 	nal_unit_type: 1
Index: 63 -- len: 1132 	-- prefix: 4 	nal_unit_type: 1
Index: 64 -- len: 886 	-- prefix: 4 	nal_unit_type: 1
Index: 65 -- len: 5280 	-- prefix: 4 	nal_unit_type: 1
Index: 66 -- len: 1898 	-- prefix: 4 	nal_unit_type: 1
Index: 67 -- len: 916 	-- prefix: 4 	nal_unit_type: 1
Index: 68 -- len: 958 	-- prefix: 4 	nal_unit_type: 1
Index: 69 -- len: 5589 	-- prefix: 4 	nal_unit_type: 1
Index: 70 -- len: 2276 	-- prefix: 4 	nal_unit_type: 1
Index: 71 -- len: 1083 	-- prefix: 4 	nal_unit_type: 1
Index: 72 -- len: 903 	-- prefix: 4 	nal_unit_type: 1
Index: 73 -- len: 5521 	-- prefix: 4 	nal_unit_type: 1
Index: 74 -- len: 2113 	-- prefix: 4 	nal_unit_type: 1
Index: 75 -- len: 972 	-- prefix: 4 	nal_unit_type: 1
Index: 76 -- len: 1198 	-- prefix: 4 	nal_unit_type: 1
Index: 77 -- len: 5574 	-- prefix: 4 	nal_unit_type: 1
Index: 78 -- len: 2166 	-- prefix: 4 	nal_unit_type: 1
Index: 79 -- len: 977 	-- prefix: 4 	nal_unit_type: 1
Index: 80 -- len: 947 	-- prefix: 4 	nal_unit_type: 1
Index: 81 -- len: 5464 	-- prefix: 4 	nal_unit_type: 1
Index: 82 -- len: 1551 	-- prefix: 4 	nal_unit_type: 1
Index: 83 -- len: 1005 	-- prefix: 4 	nal_unit_type: 1
Index: 84 -- len: 706 	-- prefix: 4 	nal_unit_type: 1
Index: 85 -- len: 5005 	-- prefix: 4 	nal_unit_type: 1
Index: 86 -- len: 1357 	-- prefix: 4 	nal_unit_type: 1
Index: 87 -- len: 687 	-- prefix: 4 	nal_unit_type: 1
Index: 88 -- len: 634 	-- prefix: 4 	nal_unit_type: 1
Index: 89 -- len: 4949 	-- prefix: 4 	nal_unit_type: 1
Index: 90 -- len: 1510 	-- prefix: 4 	nal_unit_type: 1
Index: 91 -- len: 603 	-- prefix: 4 	nal_unit_type: 1
Index: 92 -- len: 774 	-- prefix: 4 	nal_unit_type: 1
Index: 93 -- len: 4586 	-- prefix: 4 	nal_unit_type: 1
Index: 94 -- len: 1386 	-- prefix: 4 	nal_unit_type: 1
Index: 95 -- len: 603 	-- prefix: 4 	nal_unit_type: 1
Index: 96 -- len: 522 	-- prefix: 4 	nal_unit_type: 1
Index: 97 -- len: 4901 	-- prefix: 4 	nal_unit_type: 1
Index: 98 -- len: 1278 	-- prefix: 4 	nal_unit_type: 1
Index: 99 -- len: 647 	-- prefix: 4 	nal_unit_type: 1
Index: 100 -- len: 650 	-- prefix: 4 	nal_unit_type: 1
Index: 101 -- len: 5473 -- prefix: 4 	nal_unit_type: 1
Index: 102 -- len: 2068 -- prefix: 4 	nal_unit_type: 1
Index: 103 -- len: 1065 -- prefix: 4 	nal_unit_type: 1
Total is : 201432
看到没,恰好也是201432个字节。
这里的 prefix为4表明其值为0x00000001,prefix为3表明其值为0x000001。

nal_unit_type的含义见如下结构体:
//H264定义的类型 values for nal_unit_type
typedef enum {
    NALU_TYPE_SLICE     = 1, //P 帧
    NALU_TYPE_DPA      = 2,
    NALU_TYPE_DPB      = 3,
    NALU_TYPE_DPC      = 4,
    NALU_TYPE_IDR      = 5, // I帧
    NALU_TYPE_SEI      = 6, // 补充增强信息
    NALU_TYPE_SPS      = 7, // 序列参数集Sequence Parameter Set
    NALU_TYPE_PPS      = 8, // 图像参数集Picture Parameter Set
    NALU_TYPE_AUD      = 9,
    NALU_TYPE_EOSEQ     = 10,
    NALU_TYPE_EOSTREAM    = 11,
    NALU_TYPE_FILL      = 12,
#if (MVC_EXTENSION_ENABLE)
    NALU_TYPE_PREFIX    = 14,
    NALU_TYPE_SUB_SPS   = 15,
    NALU_TYPE_SLC_EXT   = 20,
    NALU_TYPE_VDRD     = 24  // View and Dependency Representation Delimiter NAL Unit
#endif
} NaluType;
具体的对比一下就可以知道了。


ffmpeg解析的帧 & 全手工解析的帧

对于第一个关键帧而言:


ffmpeg解析 全手工解析
Frame: 1, Size: 9777
Index: 1 -- len: 24 	-- prefix: 4 	nal_unit_type: 7
Index: 2 -- len: 5 	-- prefix: 4 	nal_unit_type: 8
Index: 3 -- len: 698 	-- prefix: 3 	nal_unit_type: 6
Index: 4 -- len: 9036 	-- prefix: 3 	nal_unit_type: 5
<pre name="code" class="cpp">Frame: 100, Size: 1069
 
Index: 103 -- len: 1065 -- prefix: 4 	nal_unit_type: 1

ffmpeg解析的一个帧包含的信息可不少,包括7(序列参数集), 8(图像参数集), 6(补充增强信息), 5(I帧,即关键帧)的内容以及他们的前缀(即NALU的间隔)长。
而其他的帧就是P帧了,同样的ffmepg解析的帧 等于 真实的帧内容加上 NALU的间隔。

播放该h264文件

a. 新建一个w.sdp文件,内容如下:
m=video 5234 RTP/AVP 96
a=rtpmap:96 H264
a=framerate:25
c=IN IP4 172.30.191.2
172.30.191.2是流媒体播放器接收的地址,5234是RTP接收流媒体的端口

b. 执行ffplay.exe w.sdp 或者 VLC media player打开w.sdp均可以

c. 使用3.2参考中下载的代码播放就可以了