【音视频】FFmpeg 编码H265 - 实践

一、概述

实现了读入本地yuv文件,通过libx265编码为H265格式,并存储到本地文件中

二、实现流程

准备文件

build路径下准备yuv文件

在这里插入图片描述

在项目中添加文件参数,输出为h265文件,使用libx265编码

在这里插入图片描述

初始化解码器
  • 通过传进来的libx265找到指定的编码器
codec = avcodec_find_encoder_by_name(codec_name)
;
if (!codec) {
fprintf(stderr
, "Codec '%s' not found\n"
, codec_name)
;
exit(1
)
;
}
  • 为编码器分配上下文
codec_ctx = avcodec_alloc_context3(codec)
;
if (!codec_ctx) {
fprintf(stderr
, "Could not allocate video codec context\n"
)
;
exit(1
)
;
}
  • 绑定解码器和解码器上下文
ret = avcodec_open2(codec_ctx, codec, NULL
)
;
if (ret <
0
) {
fprintf(stderr
, "Could not open codec: %s\n"
, av_err2str(ret)
)
;
exit(1
)
;
}
  • 设置编码的视频参数,如分辨率,帧率,时间基、比特率等
#
define ENCODE_TIME_BASE 1000 // 设置时间基数,编码需要根据时间来判断码率
#
define ENCODE_FRAME_RATE 25 // 设置帧率
#
define YUV_WIDTH 1280
#
define YUV_HEIGH 720
/* 设置分辨率*/
codec_ctx->width = YUV_WIDTH;
// 根据实际去写入
codec_ctx->height = YUV_HEIGH;
/* 设置time base */
codec_ctx->time_base = (AVRational){
1
, ENCODE_TIME_BASE
}
;
// 1/1000
codec_ctx->framerate = (AVRational){
ENCODE_FRAME_RATE, 1
}
;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
  • 也可以设置编码的码率,可以设置一个码率的范围
  • 也可以设置编码的缓存大小,用于在码率波动的时候做缓存
codec_ctx->bit_rate = 3000000
;
codec_ctx->rc_max_rate = 3000000
;
codec_ctx->rc_min_rate = 3000000
;
codec_ctx->rc_buffer_size = 2000000
;
  • 配置编码器的高级参数,这里指的是而外的设置
  • 比如编码模式,GOP大小,B帧大小、I帧间隔、编码profile级别、画质等等
  • preset参数是影响编码速度的,比如ultrafast编码最快,但是画质最差
codec_ctx->gop_size = 25
;
codec_ctx->max_b_frames = 0
;
codec_ctx->keyint_min = 25
;
ret = av_opt_set(codec_ctx->priv_data, "preset"
, "medium"
, 0
)
;
ret = av_opt_set(codec_ctx->priv_data, "profile"
, "main"
, 0
)
;
ret = av_opt_set(codec_ctx->priv_data, "tune"
,"film"
,0
)
;
  • 也可以通过av_opt_set的方法,将修改的内容直接发送到libx265编码器内部进行修改
ret = av_opt_set(codec_ctx->priv_data, "x265-param"
, "--keyint=25, --bframes=2"
,0
)
;
ret = av_opt_set(codec_ctx->priv_data, "x265-params"
, "--keyint=25:--frame-threads=4"
, 0
)
;
ret = av_opt_set(codec_ctx->priv_data, "x265-params"
, "--keyint=25:--bframes=2"
, 0
)
;
ret = av_opt_set(codec_ctx->priv_data, "x265-params"
, "--keyint=25:--frame-threads=4"
, 0
)
;
  • 比如我们设置了B帧为0,并且关闭了多线程,此时的延迟就为0了,观察如下
  • 可以发现,一帧数据传入编码器,立马就编码出一帧数据

在这里插入图片描述

  • 初始之外,还可以通过设置零延迟的方法,当同时必须关闭多线程
ret = av_opt_set(codec_ctx->priv_data, "tune"
,"zerolatency"
,0
)
;
  • 如果开启多线程,就会存在编码延迟,不过可以提高编码速度
  • 打印发现,传入多帧数据后,才从编码器中取出编码后的帧
ret = av_opt_set(codec_ctx->priv_data, "x265-params"
, "--keyint=25:--frame-threads=4"
, 0
)
;
  • 也可以这样设置多线程
codec_ctx->thread_count = 4
;
// 开了多线程后也会导致帧输出延迟, 需要缓存thread_count帧后再编程。 
codec_ctx->thread_type = FF_THREAD_FRAME;
// 并 设置为FF_THREAD_FRAME 

在这里插入图片描述

  • 以下的设置,是将SPS、PPS、VPS放入扩展变量里面,即codec->extradata里面
  • 此时就不会而外编码一帧了,观察打印结果
codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

启动后,没发现SPS、PPS、VPS
在这里插入图片描述

关闭后,前几帧为SPS、PPS、VPS

在这里插入图片描述

更多的libx265的设置,可以使用对应的命令查询

ffmpeg -h encoder=libx265 > libx265.log

在这里插入图片描述

编码H265
  • 打开输入、输出文件
// 打开输入和输出文件
infile = fopen(in_yuv_file, "rb"
)
;
if (!infile) {
fprintf(stderr
, "Could not open %s\n"
, in_yuv_file)
;
exit(1
)
;
}
outfile = fopen(out_h264_h265_file, "wb"
)
;
if (!outfile) {
fprintf(stderr
, "Could not open %s\n"
, out_h264_h265_file)
;
exit(1
)
;
}
  • 分配对应的AVFrame和AVPacket的内存
// 分配pkt和frame
pkt = av_packet_alloc(
)
;
if (!pkt) {
fprintf(stderr
, "Could not allocate video frame\n"
)
;
exit(1
)
;
}
frame = av_frame_alloc(
)
;
if (!frame) {
fprintf(stderr
, "Could not allocate video frame\n"
)
;
exit(1
)
;
}
  • 设置frame的参数,如分辨率、像素
// 为frame分配buffer
frame->format = codec_ctx->pix_fmt;
frame->width = codec_ctx->width;
frame->height = codec_ctx->height;
ret = av_frame_get_buffer(frame, 0
)
;
if (ret <
0
) {
fprintf(stderr
, "Could not allocate the video frame data\n"
)
;
exit(1
)
;
}
  • 通过分辨率和像素格式,计算出一帧数据对应的buffer大小,并且分配对应的缓冲区
int frame_bytes = av_image_get_buffer_size(frame->format, frame->width,
frame->height, 1
)
;
uint8_t *yuv_buf = (uint8_t *
)malloc(frame_bytes)
;
  • 循环编码文件,直到读到文件结束
  • av_frame_make_writable确保帧可用,不开启的话可能会写入失败
for (
;
;
) {
memset(yuv_buf, 0
, frame_bytes)
;
size_t read_bytes = fread(yuv_buf, 1
, frame_bytes, infile)
;
if(read_bytes <= 0
) {
printf("read file finish\n"
)
;
break
;
}
/* 确保该frame可写, 如果编码器内部保持了内存参考计数,则需要重新拷贝一个备份
目的是新写入的数据和编码器保存的数据不能产生冲突
*/
ret = av_frame_make_writable(frame)
;
if(ret != 0
) {
printf("av_frame_make_writable failed, ret = %d\n"
, ret)
;
break
;
}
int need_size = av_image_fill_arrays(frame->data, frame->linesize, yuv_buf,
frame->format,
frame->width, frame->height, 1
)
;
if(need_size != frame_bytes) {
printf("av_image_fill_arrays failed, need_size:%d, frame_bytes:%d\n"
,
need_size, frame_bytes)
;
break
;
}
pts += (ENCODE_TIME_BASE/ENCODE_FRAME_RATE)
;
// 设置pts
frame->pts = pts;
// 使用采样率作为pts的单位,具体换算成秒 pts*1/采样率
begin_time = get_time(
)
;
ret = encode(codec_ctx, frame, pkt, outfile)
;
end_time = get_time(
)
;
printf("encode time:%lldms\n"
, end_time - begin_time)
;
if(ret <
0
) {
printf("encode failed\n"
)
;
break
;
}
}
  • encode函数如下,主要是送入一帧数据,然后循环读取AVPacket,直到输出AVERROR_EOF表示当前帧编码完成
static
int encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
FILE *outfile)
{
int ret;
/* send the frame to the encoder */
if (frame)
printf("send frame pts:%3"PRId64"\n"
, frame->pts)
;
/* 通过查阅代码,使用x265进行编码时,具体缓存帧是在x265源码进行,
* 不会增加avframe对应buffer的reference*/
ret = avcodec_send_frame(enc_ctx, frame)
;
if (ret <
0
)
{
fprintf(stderr
, "Error sending a frame for encoding\n"
)
;
return -1
;
}
while (ret >= 0
)
{
ret = avcodec_receive_packet(enc_ctx, pkt)
;
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return 0
;
}
else
if (ret <
0
) {
fprintf(stderr
, "Error encoding audio frame\n"
)
;
return -1
;
}
printf("avcodec_receive_packet:pts:%3"PRId64" dts:%3"PRId64" (size:%5d)\n"
, pkt->pts, pkt->dts, pkt->size)
;
fwrite(pkt->data, 1
, pkt->size, outfile)
;
print_h265_nal_unit_type(pkt->data, pkt->size)
;
// 只针对H265
}
return 0
;
}
  • print_h265_nal_unit_type函数主要是通过H265的结构,找到startcode,然后解析NALU的头部,用于输出调试
void print_h265_nal_unit_type(uint8_t *data, size_t size)
{
int i = 0
;
while (i+3 < size ) {
if(data[i] == 0 && data[i+1]==0 && data[i+2] == 0 && data[i+3] == 1
) {
i += 4
;
printf("%02x nal_type:%d, pos:%d\n"
, data[i]
,(data[i]&
0x7e
)>>
1
, i)
;
continue
;
}
if(data[i] == 0 && data[i+1]==0 && data[i+2] == 1
) {
i += 3
;
printf("%02x nal_type:%d, pos:%d\n"
,data[i]
, (data[i]&
0x7e
)>>
1
, i)
;
continue
;
}
i++
;
}
}
冲刷编码器
  • 编码结束后,编码器内部可能还缓存了部分帧,此时需要传入NULL,将编码器中剩余的帧冲刷出来
/* 冲刷编码器 */
encode(codec_ctx, NULL
, pkt, outfile)
;
关闭文件
  • 关闭文件、并且释放相关内存,确保正确结束程序
// 关闭文件
fclose(infile)
;
fclose(outfile)
;
// 释放内存
if(yuv_buf) {
free(yuv_buf)
;
}
av_frame_free(&frame)
;
av_packet_free(&pkt)
;
avcodec_free_context(&codec_ctx)
;

完整代码

/**
* @projectName 02-encode_h265
* @brief 视频编码,从本地读取YUV数据进行H265编码
* @author Liao Qingfu
* @date 2022-09-16
*/
#
include <stdio.h>
  #
  include <stdlib.h>
    #
    include <string.h>
      #
      include <libavcodec/avcodec.h>
        #
        include <libavutil/time.h>
          #
          include <libavutil/opt.h>
            #
            include <libavutil/imgutils.h>
              #
              define ENCODE_TIME_BASE 1000 // 设置时间基数,编码需要根据时间来判断码率
              #
              define ENCODE_FRAME_RATE 25 // 设置帧率
              #
              define YUV_WIDTH 1280
              #
              define YUV_HEIGH 720
              void print_h265_nal_unit_type(uint8_t *data, size_t size)
              ;
              int64_t get_time(
              )
              {
              return av_gettime_relative(
              ) / 1000
              ;
              // 换算成毫秒
              }
              static
              int encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
              FILE *outfile)
              {
              int ret;
              /* send the frame to the encoder */
              if (frame)
              printf("send frame pts:%3"PRId64"\n"
              , frame->pts)
              ;
              /* 通过查阅代码,使用x264进行编码时,具体缓存帧是在x264源码进行,
              * 不会增加avframe对应buffer的reference*/
              ret = avcodec_send_frame(enc_ctx, frame)
              ;
              if (ret <
              0
              )
              {
              fprintf(stderr
              , "Error sending a frame for encoding\n"
              )
              ;
              return -1
              ;
              }
              while (ret >= 0
              )
              {
              ret = avcodec_receive_packet(enc_ctx, pkt)
              ;
              if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
              return 0
              ;
              }
              else
              if (ret <
              0
              ) {
              fprintf(stderr
              , "Error encoding audio frame\n"
              )
              ;
              return -1
              ;
              }
              printf("avcodec_receive_packet:pts:%3"PRId64" dts:%3"PRId64" (size:%5d)\n"
              , pkt->pts, pkt->dts, pkt->size)
              ;
              fwrite(pkt->data, 1
              , pkt->size, outfile)
              ;
              print_h265_nal_unit_type(pkt->data, pkt->size)
              ;
              // 只针对H265
              }
              return 0
              ;
              }
              /**
              * @brief 提取测试文件:ffmpeg -i test_1280x720.flv -t 5 -r 25 -pix_fmt yuv420p yuv420p_1280x720.yuv
              * 参数输入: yuv420p_1280x720.yuv yuv420p_1280x720.h265 libx265
              * @param argc
              * @param argv
              * @return
              */
              int main(
              int argc,
              char **argv)
              {
              char *in_yuv_file = NULL
              ;
              char *out_h264_h265_file = NULL
              ;
              FILE *infile = NULL
              ;
              FILE *outfile = NULL
              ;
              const
              char *codec_name = NULL
              ;
              const AVCodec *codec = NULL
              ;
              AVCodecContext *codec_ctx= NULL
              ;
              AVFrame *frame = NULL
              ;
              AVPacket *pkt = NULL
              ;
              int ret = 0
              ;
              if (argc <
              4
              ) {
              fprintf(stderr
              , "Usage: %s <input_file out_file codec_name >, argc:%d\n"
                ,
                argv[0]
                , argc)
                ;
                return 0
                ;
                }
                in_yuv_file = argv[1]
                ;
                // 输入YUV文件
                out_h264_h265_file = argv[2]
                ;
                codec_name = argv[3]
                ;
                /* 查找指定的编码器 */
                codec = avcodec_find_encoder_by_name(codec_name)
                ;
                if (!codec) {
                fprintf(stderr
                , "Codec '%s' not found\n"
                , codec_name)
                ;
                exit(1
                )
                ;
                }
                codec_ctx = avcodec_alloc_context3(codec)
                ;
                if (!codec_ctx) {
                fprintf(stderr
                , "Could not allocate video codec context\n"
                )
                ;
                exit(1
                )
                ;
                }
                /* 设置分辨率*/
                codec_ctx->width = YUV_WIDTH;
                // 根据实际去写入
                codec_ctx->height = YUV_HEIGH;
                /* 设置time base */
                codec_ctx->time_base = (AVRational){
                1
                , ENCODE_TIME_BASE
                }
                ;
                // 1/1000
                codec_ctx->framerate = (AVRational){
                ENCODE_FRAME_RATE, 1
                }
                ;
                /* 设置I帧间隔
                * 如果frame->pict_type设置为AV_PICTURE_TYPE_I, 则忽略gop_size的设置,一直当做I帧进行编码
                */
                codec_ctx->gop_size = 25
                ;
                // I帧间隔, H265单独设置这里不起作用
                codec_ctx->keyint_min = 25
                ;
                codec_ctx->max_b_frames = 0
                ;
                // 如果不想包含B帧则设置为0
                codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
                //
                if (codec->id == AV_CODEC_ID_H264) {
                // 相关的参数可以参考libx264.c的 AVOption options
                // ultrafast all encode time:2270ms
                // medium all encode time:5815ms
                // veryslow all encode time:19836ms
                ret = av_opt_set(codec_ctx->priv_data, "preset"
                , "medium"
                , 0
                )
                ;
                if(ret != 0
                ) {
                printf("av_opt_set preset failed\n"
                )
                ;
                }
                ret = av_opt_set(codec_ctx->priv_data, "profile"
                , "main"
                , 0
                )
                ;
                // 默认是high
                if(ret != 0
                ) {
                printf("av_opt_set profile failed\n"
                )
                ;
                }
                // ret = av_opt_set(codec_ctx->priv_data, "tune","zerolatency",0); // 直播是才使用该设置
                // ret = av_opt_set(codec_ctx->priv_data, "tune","film",0); // 画质film
                if(ret != 0
                ) {
                printf("av_opt_set tune failed\n"
                )
                ;
                }
                }
                else
                if (codec->id == AV_CODEC_ID_H265) {
                // 相关的参数可以参考libx265.c的 AVOption options
                // ultrafast all encode time:
                // medium all encode time:
                // veryslow all encode time:
                ret = av_opt_set(codec_ctx->priv_data, "preset"
                , "medium"
                , 0
                )
                ;
                if(ret != 0
                ) {
                printf("av_opt_set preset failed\n"
                )
                ;
                }
                ret = av_opt_set(codec_ctx->priv_data, "profile"
                , "main"
                , 0
                )
                ;
                // 默认是high
                if(ret != 0
                ) {
                printf("av_opt_set profile failed\n"
                )
                ;
                }
                ret = av_opt_set(codec_ctx->priv_data, "tune"
                ,"zerolatency"
                ,0
                )
                ;
                // 直播是才使用该设置
                // ret = av_opt_set(codec_ctx->priv_data, "tune","film",0); // 画质film
                if(ret != 0
                ) {
                printf("av_opt_set tune failed\n"
                )
                ;
                }
                // libx265/source\common\param.cpp
                // ret = av_opt_set(codec_ctx->priv_data, "x265-param", "--keyint=25, --bframes=2",0);
                // ret = av_opt_set(codec_ctx->priv_data, "x265-params", "--keyint=25:--frame-threads=4", 0);
                // ret = av_opt_set(codec_ctx->priv_data, "x265-params", "--keyint=25:--bframes=2", 0);
                // ret = av_opt_set(codec_ctx->priv_data, "x265-params", "--keyint=25:--frame-threads=4", 0);
                if(ret != 0
                ) {
                printf("av_opt_set x265-param failed\n"
                )
                ;
                return -1
                ;
                }
                }
                else {
                printf("no support the codec :%s\n"
                , codec_name)
                ;
                return -1
                ;
                }
                /*
                * 设置编码器参数
                */
                /* 设置bitrate */
                codec_ctx->bit_rate = 3000000
                ;
                //3000k
                // codec_ctx->rc_max_rate = 3000000;
                // codec_ctx->rc_min_rate = 3000000;
                // codec_ctx->rc_buffer_size = 2000000;
                // codec_ctx->thread_count = 4; // 开了多线程后也会导致帧输出延迟, 需要缓存thread_count帧后再编程。
                // codec_ctx->thread_type = FF_THREAD_FRAME; // 并 设置为FF_THREAD_FRAME
                /* 对于H264 AV_CODEC_FLAG_GLOBAL_HEADER 设置则只包含I帧,此时sps pps需要从codec_ctx->extradata读取
                * 不设置则每个I帧都带 sps pps sei
                */
                codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
                // 存本地文件时不要去设置
                /* 将codec_ctx和codec进行绑定 */
                ret = avcodec_open2(codec_ctx, codec, NULL
                )
                ;
                if (ret <
                0
                ) {
                fprintf(stderr
                , "Could not open codec: %s\n"
                , av_err2str(ret)
                )
                ;
                exit(1
                )
                ;
                }
                printf("thread_count: %d, thread_type:%d\n"
                , codec_ctx->thread_count, codec_ctx->thread_type)
                ;
                // 打开输入和输出文件
                infile = fopen(in_yuv_file, "rb"
                )
                ;
                if (!infile) {
                fprintf(stderr
                , "Could not open %s\n"
                , in_yuv_file)
                ;
                exit(1
                )
                ;
                }
                outfile = fopen(out_h264_h265_file, "wb"
                )
                ;
                if (!outfile) {
                fprintf(stderr
                , "Could not open %s\n"
                , out_h264_h265_file)
                ;
                exit(1
                )
                ;
                }
                // 分配pkt和frame
                pkt = av_packet_alloc(
                )
                ;
                if (!pkt) {
                fprintf(stderr
                , "Could not allocate video frame\n"
                )
                ;
                exit(1
                )
                ;
                }
                frame = av_frame_alloc(
                )
                ;
                if (!frame) {
                fprintf(stderr
                , "Could not allocate video frame\n"
                )
                ;
                exit(1
                )
                ;
                }
                // 为frame分配buffer
                frame->format = codec_ctx->pix_fmt;
                frame->width = codec_ctx->width;
                frame->height = codec_ctx->height;
                ret = av_frame_get_buffer(frame, 0
                )
                ;
                if (ret <
                0
                ) {
                fprintf(stderr
                , "Could not allocate the video frame data\n"
                )
                ;
                exit(1
                )
                ;
                }
                // 计算出每一帧的数据 像素格式 * 宽 * 高
                // 1382400
                int frame_bytes = av_image_get_buffer_size(frame->format, frame->width,
                frame->height, 1
                )
                ;
                printf("frame_bytes %d\n"
                , frame_bytes)
                ;
                uint8_t *yuv_buf = (uint8_t *
                )malloc(frame_bytes)
                ;
                if(!yuv_buf) {
                printf("yuv_buf malloc failed\n"
                )
                ;
                return 1
                ;
                }
                int64_t begin_time = get_time(
                )
                ;
                int64_t end_time = begin_time;
                int64_t all_begin_time = get_time(
                )
                ;
                int64_t all_end_time = all_begin_time;
                int64_t pts = 0
                ;
                printf("start enode\n"
                )
                ;
                for (
                ;
                ;
                ) {
                memset(yuv_buf, 0
                , frame_bytes)
                ;
                size_t read_bytes = fread(yuv_buf, 1
                , frame_bytes, infile)
                ;
                if(read_bytes <= 0
                ) {
                printf("read file finish\n"
                )
                ;
                break
                ;
                }
                /* 确保该frame可写, 如果编码器内部保持了内存参考计数,则需要重新拷贝一个备份
                目的是新写入的数据和编码器保存的数据不能产生冲突
                */
                ret = av_frame_make_writable(frame)
                ;
                if(ret != 0
                ) {
                printf("av_frame_make_writable failed, ret = %d\n"
                , ret)
                ;
                break
                ;
                }
                int need_size = av_image_fill_arrays(frame->data, frame->linesize, yuv_buf,
                frame->format,
                frame->width, frame->height, 1
                )
                ;
                if(need_size != frame_bytes) {
                printf("av_image_fill_arrays failed, need_size:%d, frame_bytes:%d\n"
                ,
                need_size, frame_bytes)
                ;
                break
                ;
                }
                pts += (ENCODE_TIME_BASE/ENCODE_FRAME_RATE)
                ;
                // 设置pts
                frame->pts = pts;
                // 使用采样率作为pts的单位,具体换算成秒 pts*1/采样率
                begin_time = get_time(
                )
                ;
                ret = encode(codec_ctx, frame, pkt, outfile)
                ;
                end_time = get_time(
                )
                ;
                printf("encode time:%lldms\n"
                , end_time - begin_time)
                ;
                if(ret <
                0
                ) {
                printf("encode failed\n"
                )
                ;
                break
                ;
                }
                }
                /* 冲刷编码器 */
                encode(codec_ctx, NULL
                , pkt, outfile)
                ;
                all_end_time = get_time(
                )
                ;
                printf("all encode time:%lldms\n"
                , all_end_time - all_begin_time)
                ;
                // 关闭文件
                fclose(infile)
                ;
                fclose(outfile)
                ;
                // 释放内存
                if(yuv_buf) {
                free(yuv_buf)
                ;
                }
                av_frame_free(&frame)
                ;
                av_packet_free(&pkt)
                ;
                avcodec_free_context(&codec_ctx)
                ;
                printf("main finish, please enter Enter and exit\n"
                )
                ;
                getchar(
                )
                ;
                return 0
                ;
                }
                void print_h265_nal_unit_type(uint8_t *data, size_t size)
                {
                int i = 0
                ;
                while (i+3 < size ) {
                if(data[i] == 0 && data[i+1]==0 && data[i+2] == 0 && data[i+3] == 1
                ) {
                i += 4
                ;
                printf("%02x nal_type:%d, pos:%d\n"
                , data[i]
                ,(data[i]&
                0x7e
                )>>
                1
                , i)
                ;
                continue
                ;
                }
                if(data[i] == 0 && data[i+1]==0 && data[i+2] == 1
                ) {
                i += 3
                ;
                printf("%02x nal_type:%d, pos:%d\n"
                ,data[i]
                , (data[i]&
                0x7e
                )>>
                1
                , i)
                ;
                continue
                ;
                }
                i++
                ;
                }
                }

更多资料:https://github.com/0voice

posted on 2025-10-05 16:02  slgkaifa  阅读(4)  评论(0)    收藏  举报

导航