• FFmpeg对H246进行编解码的实现


    avformat_open_input() 函数是用于打开媒体文件并获取媒体文件信息的函数,该函数定义在libavformat/avformat.h中。
    函数原型为:

    1. int avformat_open_input(
    2. AVFormatContext **ps,
    3. const char *url,
    4. AVInputFormat *fmt,
    5. AVDictionary **options);
    6. 函数的参数含义如下:
    7. ps: AVFormatContext结构体的指针。该参数用于存储打开的媒体文件的信息。
    8. 当该函数成功返回时,AVFormatContext结构体中将存储媒体文件的相关信息。
    9. url:要打开的媒体文件的URL。可以是本地文件路径,也可以是HTTP URL或其他协议的URL。
    10. fmt:AVInputFormat结构体的指针,用于指定媒体文件的格式。如果该参数为NULL
    11. 则根据文件扩展名自动选择输入格式。
    12. options:AVDictionary结构体的指针,用于传递打开媒体文件时的选项。

    -------------------------------------------------------

    比较重要结构体介绍

    AVFormatContext 结构体。该参数用于存储打开的媒体文件的信息。当该函数成功返回时,AVFormatContext结构体中将存储媒体文件的相关信息。是FFmpeg 解封装(flv,mp4,rmvb,avi)功能的结构体。

    1. typedef struct AVFormatContext{
    2. struct AVInputFormat *iformat; //输入数据的封装格式
    3. AVIOContext *pb; //输入数据的缓存
    4. unsigned int nb_streams; //视音频流的个数
    5. AVStream **streams; //视音频流
    6. char filename[1024]; //文件名
    7. int64_t duration; //时长(单位:微秒ms,转换为秒需要除以1_000_000)
    8. int bit_rate; //比特率(单位bps,转换为kbps需要除以1_000)
    9. AVDictionary *metadata; //元数据
    10. }AVFormatContext

    -----------------------------------------------------------

    AVCodecContext是包含变量较多的结构体,AVCodecContext中很多的参数是编码的时候使用的,而不是解码的时候使用的。

    1. typedef struct AVCodecContext{
    2. enum AVMediaType codec_type:编解码器的类型(视频,音频...)
    3. struct AVCodec *codec:采用的解码器AVCodec(H.264,MPEG2...)
    4. int bit_rate:平均比特率
    5. uint8_t *extradata; int extradata_size:针对特定编码器包含的附加信息(例如对于H.264解码器来
    6. 说,存储SPS,PPS等)
    7. AVRational time_base:根据该参数,可以把PTS转化为实际的时间(单位为秒s)
    8. int width, height:如果是视频的话,代表宽和高
    9. int refs:运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)
    10. int sample_rate:采样率(音频)
    11. int channels:声道数(音频)
    12. enum AVSampleFormat sample_fmt:采样格式
    13. int profile:型(H.264里面就有,其他编码标准应该也有)
    14. int level:级(和profile差不太多)
    15. }AVCodecContext

    ----------------------------------------------------

    AVCodec结构体是FFmpeg比较重要的结构体之一,主要用于存储编解码器的信息。

    1. typedef struct AVCodec
    2. {
    3. const char *name:编解码器的名字,比较短
    4. const char *long_name:编解码器的名字,全称,比较长
    5. enum AVMediaType type:指明了类型,是视频,音频,还是字幕
    6. enum AVCodecID id:ID,不重复
    7. const AVRational *supported_framerates:支持的帧率(仅视频)
    8. const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频)
    9. const int *supported_samplerates:支持的采样率(仅音频)
    10. const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)
    11. const uint64_t *channel_layouts:支持的声道数(仅音频)
    12. int priv_data_size:私有数据的大小
    13. }

    --------------------------------------------------

    AVMediaType编解码器类型:

    1. enum AVMediaType {
    2. AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA
    3. AVMEDIA_TYPE_VIDEO,
    4. AVMEDIA_TYPE_AUDIO,
    5. AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous
    6. AVMEDIA_TYPE_SUBTITLE,
    7. AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse
    8. AVMEDIA_TYPE_NB
    9. };

    ====================================
     FFmpeg对H246进行编解码的实现

    1. #include "libavutil/adler32.h"
    2. #include "libavcodec/avcodec.h"
    3. #include "libavformat/avformat.h"
    4. #include "libavutil/imgutils.h"
    5. #include "libavutil/timestamp.h"
    6. static int video_decode_example(const char *input_filename)
    7. {
    8. const AVCodec *codec = NULL;
    9. AVCodecContext *ctx= NULL;
    10. AVCodecParameters *origin_par = NULL;
    11. AVFrame *fr = NULL;
    12. uint8_t *byte_buffer = NULL;
    13. AVPacket *pkt;
    14. AVFormatContext *fmt_ctx = NULL;
    15. int number_of_written_bytes;
    16. int video_stream;
    17. int byte_buffer_size;
    18. int i = 0;
    19. int result;
    20. result = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);
    21. if (result < 0) {
    22. av_log(NULL, AV_LOG_ERROR, "Can't open file\n");
    23. return result;
    24. }
    25. result = avformat_find_stream_info(fmt_ctx, NULL);
    26. if (result < 0) {
    27. av_log(NULL, AV_LOG_ERROR, "Can't get stream info\n");
    28. return result;
    29. }
    30. video_stream = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    31. if (video_stream < 0) {
    32. av_log(NULL, AV_LOG_ERROR, "Can't find video stream in input file\n");
    33. return -1;
    34. }
    35. origin_par = fmt_ctx->streams[video_stream]->codecpar;
    36. codec = avcodec_find_decoder(origin_par->codec_id);
    37. if (!codec) {
    38. av_log(NULL, AV_LOG_ERROR, "Can't find decoder\n");
    39. return -1;
    40. }
    41. ctx = avcodec_alloc_context3(codec);
    42. if (!ctx) {
    43. av_log(NULL, AV_LOG_ERROR, "Can't allocate decoder context\n");
    44. return AVERROR(ENOMEM);
    45. }
    46. result = avcodec_parameters_to_context(ctx, origin_par);
    47. if (result) {
    48. av_log(NULL, AV_LOG_ERROR, "Can't copy decoder context\n");
    49. return result;
    50. }
    51. result = avcodec_open2(ctx, codec, NULL);
    52. if (result < 0) {
    53. av_log(ctx, AV_LOG_ERROR, "Can't open decoder\n");
    54. return result;
    55. }
    56. fr = av_frame_alloc();
    57. if (!fr) {
    58. av_log(NULL, AV_LOG_ERROR, "Can't allocate frame\n");
    59. return AVERROR(ENOMEM);
    60. }
    61. pkt = av_packet_alloc();
    62. if (!pkt) {
    63. av_log(NULL, AV_LOG_ERROR, "Cannot allocate packet\n");
    64. return AVERROR(ENOMEM);
    65. }
    66. byte_buffer_size = av_image_get_buffer_size(ctx->pix_fmt, ctx->width, ctx->height, 16);
    67. byte_buffer = av_malloc(byte_buffer_size);
    68. if (!byte_buffer) {
    69. av_log(NULL, AV_LOG_ERROR, "Can't allocate buffer\n");
    70. return AVERROR(ENOMEM);
    71. }
    72. printf("#tb %d: %d/%d\n", video_stream, fmt_ctx->streams[video_stream]->time_base.num, fmt_ctx->streams[video_stream]->time_base.den);
    73. i = 0;
    74. result = 0;
    75. while (result >= 0) {
    76. result = av_read_frame(fmt_ctx, pkt);
    77. if (result >= 0 && pkt->stream_index != video_stream) {
    78. av_packet_unref(pkt);
    79. continue;
    80. }
    81. if (result < 0)
    82. result = avcodec_send_packet(ctx, NULL);
    83. else {
    84. if (pkt->pts == AV_NOPTS_VALUE)
    85. pkt->pts = pkt->dts = i;
    86. result = avcodec_send_packet(ctx, pkt);
    87. }
    88. av_packet_unref(pkt);
    89. if (result < 0) {
    90. av_log(NULL, AV_LOG_ERROR, "Error submitting a packet for decoding\n");
    91. return result;
    92. }
    93. while (result >= 0) {
    94. result = avcodec_receive_frame(ctx, fr);
    95. if (result == AVERROR_EOF)
    96. goto finish;
    97. else if (result == AVERROR(EAGAIN)) {
    98. result = 0;
    99. break;
    100. } else if (result < 0) {
    101. av_log(NULL, AV_LOG_ERROR, "Error decoding frame\n");
    102. return result;
    103. }
    104. number_of_written_bytes = av_image_copy_to_buffer(byte_buffer, byte_buffer_size,
    105. (const uint8_t* const *)fr->data, (const int*) fr->linesize,
    106. ctx->pix_fmt, ctx->width, ctx->height, 1);
    107. if (number_of_written_bytes < 0) {
    108. av_log(NULL, AV_LOG_ERROR, "Can't copy image to buffer\n");
    109. av_frame_unref(fr);
    110. return number_of_written_bytes;
    111. }
    112. printf("%d, %s, %s, %8"PRId64", %8d, 0x%08"PRIx32"\n", video_stream,
    113. av_ts2str(fr->pts), av_ts2str(fr->pkt_dts), fr->duration,
    114. number_of_written_bytes, av_adler32_update(0, (const uint8_t*)byte_buffer, number_of_written_bytes));
    115. av_frame_unref(fr);
    116. }
    117. i++;
    118. }
    119. finish:
    120. av_packet_free(&pkt);
    121. av_frame_free(&fr);
    122. avformat_close_input(&fmt_ctx);
    123. avcodec_free_context(&ctx);
    124. av_freep(&byte_buffer);
    125. return 0;
    126. }
    127. int main(int argc, char **argv)
    128. {
    129. if (argc < 2)
    130. {
    131. av_log(NULL, AV_LOG_ERROR, "Incorrect input\n");
    132. return 1;
    133. }
    134. if (video_decode_example(argv[1]) != 0)
    135. return 1;
    136. return 0;
    137. }
  • 相关阅读:
    Python的web自动化学习(三)Selenium的显性、隐形等待
    css让元素垂直居中
    高云FPGA系列教程(6):ARM定时器使用
    python中scipy求解方法
    Vue 源码解读(8)—— 编译器 之 解析(下)
    CAS:190598-55-1_Biotin sulfo-N-hydroxysuccinimide ester生物素化试
    ROS2专题【02】:Ubuntu上安装ROS2
    ThreadLocal的使用及原理解析
    Unity 关节:铰链、弹簧、固定、物理材质:摩檫力、 特效:拖尾、
    【文本检测与识别白皮书-3.2】第二节:基于注意力机制和CTC的场景文本识别方法的对比
  • 原文地址:https://blog.csdn.net/weixin_44651073/article/details/136605247