ffmpeg解码音视频过程(附代码)

0. 引言

最近一直在使用和学习ffmpeg. 工作中需要拉流解码, 获取音频和视频数据. 这些都是使用ffmpeg处理.

  因为对ffmpeg接触不多, 用的不深, 在使用的过程中经常遇到不太懂的地方, 就会花费很多时间去查阅资料. 所以自己对用到的知识点总结一下, 方便自己以后再重复用到时能够方便找到.

  环境: ubuntu16.04, 已安装ffmpeg依赖库. gcc编译工具.

ffmpeg解码过程中用到了两个很重要的结构体, 这两个结构体比较复杂, 用到的次数也非常多, 以后我单独写一篇进行总结.

    • AVPacket 保存未解码的数据.
    • AVFrame 保存解码后的数据.

1. 解码流程

2. 代码

  1 //***************************************************************
  2 // @file:    test.c
  3 // @author:  dingfang
  4 // @date    2019-07-24 18:55:16
  5 //***************************************************************
  6
  7 #include <stdio.h>
  8
  9 #ifdef __cplusplus
 10 extern "C"
 11 {
 12 #endif
 13 #include <libavcodec/avcodec.h>
 14 #include <libavformat/avformat.h>
 15 #ifdef __cplusplus
 16 };
 17 #endif
 18
 19 int openCodecContext(const AVFormatContext *pFormatCtx, int *pStreamIndex, enum AVMediaType type, AVCodecContext **ppCodecCtx)
 20 {
 21     int streamIdx = -1;
 22     // 获取流下标
 23     for (int i = 0; i < pFormatCtx->nb_streams; i++)
 24     {
 25         if (pFormatCtx->streams[i]->codec->codec_type == type)
 26         {
 27             streamIdx = i;
 28             break;
 29         }
 30     }
 31     if (streamIdx == -1)
 32     {
 33         printf("find video stream failed!\n");
 34         exit(-2);
 35     }
 36     // 寻找解码器
 37     AVCodecContext  *pCodecCtx = pFormatCtx->streams[streamIdx]->codec;
 38     AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
 39     if (NULL == pCodec)
 40     {
 41         printf("avcode find decoder failed!\n");
 42         exit(-2);
 43     }
 44
 45     //打开解码器
 46     if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
 47     {
 48         printf("avcode open failed!\n");
 49         exit(-2);
 50     }
 51     *ppCodecCtx        = pCodecCtx;
 52     *pStreamIndex    = streamIdx;
 53
 54     return 0;
 55 }
 56
 57 int main(void)
 58 {
 59     AVFormatContext    *pInFormatCtx    = NULL;
 60     AVCodecContext  *pVideoCodecCtx    = NULL;
 61     AVCodecContext  *pAudioCodecCtx    = NULL;
 62     AVPacket *pPacket    = NULL;
 63     AVFrame *pFrame        = NULL;
 64     int ret;
 65     /* 支持本地文件和网络url */
 66     const char streamUrl[] = "./test.flv";
 67
 68     /* 1. 注册 */
 69     av_register_all();
 70
 71     pInFormatCtx = avformat_alloc_context();
 72
 73     /* 2. 打开流 */
 74     if(avformat_open_input(&pInFormatCtx, streamUrl, NULL, NULL) != 0)
 75     {
 76         printf("Couldn‘t open input stream.\n");
 77         return -1;
 78     }
 79
 80     /* 3. 获取流的信息 */
 81     if(avformat_find_stream_info(pInFormatCtx, NULL) < 0)
 82     {
 83         printf("Couldn‘t find stream information.\n");
 84         return -1;
 85     }
 86
 87     int videoStreamIdx = -1;
 88     int audioStreamIdx = -1;
 89     /* 4. 寻找并打开解码器 */
 90     openCodecContext(pInFormatCtx, &videoStreamIdx, AVMEDIA_TYPE_VIDEO, &pVideoCodecCtx);
 91     openCodecContext(pInFormatCtx, &audioStreamIdx, AVMEDIA_TYPE_AUDIO, &pAudioCodecCtx);
 92
 93     pPacket    = av_packet_alloc();
 94     pFrame    = av_frame_alloc();
 95
 96     int cnt = 30;
 97     while (cnt--)
 98     {
 99         /* 5. 读流数据, 未解码的数据存放于pPacket */
100         ret = av_read_frame(pInFormatCtx, pPacket);
101         if (ret < 0)
102         {
103             printf("av_read_frame error\n");
104             break;
105         }
106
107         /* 6. 解码, 解码后的数据存放于pFrame */
108         /* 视频解码 */
109         if (pPacket->stream_index == videoStreamIdx)
110         {
111             avcodec_decode_video2(pVideoCodecCtx, pFrame, &ret, pPacket);
112             if (ret == 0)
113             {
114                 printf("video decodec error!\n");
115                 continue;
116             }
117             printf("* * * * * * video * * * * * * * * *\n");
118             printf("___height: [%d]\n", pFrame->height);
119             printf("____width: [%d]\n", pFrame->width);
120             printf("pict_type: [%d]\n", pFrame->pict_type);
121             printf("___format: [%d]\n", pFrame->format);
122             printf("* * * * * * * * * * * * * * * * * * *\n\n");
123         }
124
125         /* 音频解码 */
126         if (pPacket->stream_index == audioStreamIdx)
127         {
128             avcodec_decode_audio4(pAudioCodecCtx, pFrame, &ret, pPacket);
129             if (ret < 0)
130             {
131                 printf("audio decodec error!\n");
132                 continue;
133             }
134             printf("* * * * * * audio * * * * * * * * * *\n");
135             printf("____nb_samples: [%d]\n", pFrame->nb_samples);
136             printf("__samples_rate: [%d]\n", pFrame->sample_rate);
137             printf("channel_layout: [%lu]\n", pFrame->channel_layout);
138             printf("________format: [%d]\n", pFrame->format);
139             printf("* * * * * * * * * * * * * * * * * * *\n\n");
140         }
141         av_packet_unref(pPacket);
142     }
143
144     av_frame_free(&pFrame);
145     av_packet_free(&pPacket);
146     avcodec_close(pVideoCodecCtx);
147     avcodec_close(pAudioCodecCtx);
148     avformat_close_input(&pInFormatCtx);
149
150     return 0;
151 }

该代码不能直接编译, 编译需要依赖ffmpeg库. 包含ffmpeg动态库和makefile文件的压缩包地址: 点我下载

解压后, 进入目录, 使用make命令即可编译.

3. 函数说明

这里就几个比较重要的函数简单介绍一下.

av_register_all()        /* 使用ffmpeg几乎都要调用这一个函数, 注册ffmpeg各种编解码器, 复用器等. */

avformat_open_input()      /* 该函数用于打开本地多媒体文件或者网络流媒体url */

avformat_find_stream_info()   /* 该函数用于读取一部分音视频数据并且获得一些相关的信息 */

avcodec_find_decoder()    /* 由codec_id或者解码器名称来寻找对应的解码器 */

avcodec_open2()        /* 初始化解码器 */

av_read_frame()        /* 读流数据, 读出来的是压缩数据, 存放于AVPacket */

avcodec_decode_video2()    /* 视频解码 解码后数据为原始数据, 存放于AVFrame */

avcodec_decode_audio4()    /* 音频解码 解码后数据为原始数据, 存放于AVFrame */

原文地址:https://www.cnblogs.com/changdingfang/p/11243065.html

时间: 2024-11-06 03:31:25

ffmpeg解码音视频过程(附代码)的相关文章

FFmpeg开发实战(五):FFmpeg 抽取音视频的视频数据

如何使用FFmpeg抽取音视频的视频数据,代码如下: // FFmpegTest.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. // #include "pch.h" #include <iostream> #include "AACFormat.h" #define __STDC_CONSTANT_MACROS #define __STDC_FORMAT_MACROS // For extractVide

使用FFmpeg进行音视频编解码

FFmpeg下载地址:http://ffmpeg.org/ 跳转后进入http://ffmpeg.zeranoe.com/builds/,下载Static版本 解压缩后如下图 说明:ffmpeg是下载后的文件包 3.MP4是待转换的MP4文件 打开命令行工工具 输入一下命令 :{classpath}\ffmpeg\bin\ffmpeg.exe -i {classpath}\3.mp4 -acodec libvorbis {classpath}\3.ogg classpath:为路径地址 以上为例

ffmpeg 如何音视频同步

转自:http://blog.csdn.net/yangzhiloveyou/article/details/8832516 output_example.c 中AV同步的代码如下(我的代码有些修改),这个实现相当简单,不过挺说明问题. 音视频同步方法:选择一个参考时钟,参考时钟上的时间是线性递增的,生成数据流时依据参考时钟上的时间给每个数据块 都打上时间戳(一般包括开始时间和结束时间).在播放时,读取数据块上的时间戳,同时参考当前参考时钟上的时间来安 排播放.数据流不会发生参考关系. 步骤:1

如何使用ffmpeg进行音视频裁剪命令和音视频合成命令

音视频剪裁命令 ffmpeg -i input.mp4 -ss 00:00:00 -t 10 out.ts -i : 指定视频 -ss : 开始时间 -t : 指定裁剪的秒数 音视频合并的命令 ffmpeg -f concat -i inputs.txt out.flv -f concat : 指定为合并的指令 -i : 指定需要操作的命令 inputs.txt: 指定合并的文件,文件格式 file "文件名称" 举例inputs.txt file “1.ts” file “2.ts”

[ffmpeg] 抽取音视频数据

参考自: [FFmpeg抽取视频h264数据]  https://www.jianshu.com/p/11cdf48ec248 [FFmpeg抽取音频数据?]  https://www.jianshu.com/p/5337260efd97 [ADTS详解]  https://www.jianshu.com/p/af0165f923e9 音频流 代码实现: 1 #include "stdafx.h" 2 ? 3 #define DDug av_log(NULL, AV_LOG_WARNI

mac下ffmpeg打开音视频设备(开启音视频设备访问限制)

The app's Info.plist must contain an NSMicrophoneUsageDescription key with a string value explaining to the user how the app uses this data 在mac上用Xcode用ffmpeg的API: ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options); 报上述错误:该应用已崩溃,因为

Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)

项目地址,求starhttps://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpeg%E6%92%AD%E6%94%BE%E9%9F%B3%E4%B9%90%EF%BC%88%E4%BF%9D%E7%A8%8B%E5%BA%8F%E4%B8%8D%E6%AD%BB%EF%BC%89 这个是FFmpeg解码出音频,给AudioTrack播放,这回才算是java与c语言之间合作 这回我们将会从c++里调用java函数,下面就

FFmpeg音视频核心技术精讲与实战

第1章 课程导学与准备工作全民娱乐时代,需要音视频等多媒体产品层出不穷,但会处理音视频数据的工程师却极度匮乏,进入音视频开发领域正当时,这门课程就是为这样的你而生.来吧!加入我们,成就更好的自己.1-1 课前必读(不看会错过一个亿)1-2 课程导学1-3 音视频的应用范围与播放器架构讲解(选看)1-4 什么是ffmpeg?它能做什么?(选看)1-5 ffmpeg下载,编译与安装1-6 Windows下安装 FFmpeg1-7 ffmpeg命令大全文档 第2章 FFmpeg常用命令实战本章讲解如何

音视频之ffmpeg时间基

FFmpeg中有个比较重要的概念就是时间基. ffmpeg本身有个时间基,视频输入流有时间基,输出流有时间基,音频也是相同道理. 主要的目的是方便他们自己内部计算. 我们先拿视频播放器来举例,其中要对时间进行处理的是视频的时间,音频的时间,然后两者要进行同步. 我们先看timebase的结构体: 这就是一个分数 我们播放一个视频打印日志发现 视频的时间基是1/12800,这个12800怎么算出来的我是真不知道 音频时间基是1/48000,这个还好理解,音频采样率就是48000,也就是一秒钟采样4