FFMPEG基础学习

视频解码,并且输出到文件。

我通过雷霄骅的博客学习FFMPEG,在学习过程中发现“雷神”的代码由于版本的问题,很多代码已经无法在FFMPEG——4.2.2版本中使用,而在网上也有很多教程是基于FFMPEG——3.x.x版本的,因此,特别写了这篇文章,解决学习“雷神”博客代码在4.x.x上编译无法通过的问题。本篇文章最下面的代码,配置好环境之后,直接复制,然后修改输入视频文件的路径,就可以运行。

特别是在4.x.x版本中av_register_all();这个函数完全不需要。

本程序的输入文件只要是编码数据是H264;AAC,解码数据是YUV420P;PCM格式的都可以正常运行。

本程序输出的文件格式是:H264;YUV420P;AAC;PCM。

比较大的改动举例:

1、关于AVFrame结构体在转码过程中的初始化:

雷霄骅的例子代码如下:

    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);

这些在新版本无法编译,很多声明已经否决。

我修改后的初始化代码如下:

 AVFrame* p_z_p_deco_AVFrame = av_frame_alloc();p_z_p_deco_AVFrame->width = p_input_file_v_AVCodecContext->width;p_z_p_deco_AVFrame->height = p_input_file_v_AVCodecContext->height;p_z_p_deco_AVFrame->format = AV_PIX_FMT_YUV420P;av_frame_get_buffer(p_z_p_deco_AVFrame, 4);

以下是ffmpeg4.2.2版本中对于AVFrame结构体的说明。

/*** Allocate an AVFrame and set its fields to default values.  The resulting* struct must be freed using av_frame_free().** @return An AVFrame filled with default values or NULL on failure.** @note this only allocates the AVFrame itself, not the data buffers. Those* must be allocated through other means, e.g. with av_frame_get_buffer() or* manually.*/
AVFrame *av_frame_alloc(void);

2、关于编码和解码

雷霄骅的例子使用的函数如下:

int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,int *got_picture_ptr,const AVPacket *avpkt);

FFMPEG——4.2.2版本用的解码的函数是:

int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);

FFMPEG——4.2.2版本用的编码函数是:

int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);

3、关于在解码过程中AVPacket的内存释放问题

使用如下函数读取一帧数据以后,*pkt指向的内存空间在读取的过程中不能直接释放,需要使用void av_packet_unref(AVPacket *pkt)来减少引用,在左后所有数据读完之后,才用void av_packet_free(AVPacket **pkt)函数释放掉空间。

int av_read_frame(AVFormatContext *s, AVPacket *pkt);

其它的有关版本问题就不一一列举,最后推荐初学者去看看《基于FFmpeg+SDL的视频播放器的制作——雷霄骅》这些视频,有利于学习FFMPEG。本段代码是基于视频中前四小节内容的更新。

感谢雷霄骅。

/**
解码实例时间:2020年4月ffmpeg版本:4.2.2
vs版本:Microsoft Visual Studio Enterprise 2019
开发语言:C++特别声明:本程序是我通过学习雷霄骅 Lei Xiaohua的博客而编写的,因此,在此向雷霄骅表示敬意。雷霄骅的博客地址:https://blog.csdn.net/leixiaohua1020
所需知识背景:“视音频数据处理入门:RGB、YUV像素数据处理”,链接地址:https://blog.csdn.net/leixiaohua1020/article/details/50534150“视音频数据处理入门:PCM音频采样数据处理”,链接地址:https://blog.csdn.net/leixiaohua1020/article/details/50534316“视音频数据处理入门:H.264视频码流解析”,链接地址:https://blog.csdn.net/leixiaohua1020/article/details/50534369“视音频数据处理入门:AAC音频码流解析”,链接地址:https://blog.csdn.net/leixiaohua1020/article/details/50535042
说明:本程序实现了解码本地视频,并且分别输出解码的音视频文件到文件。通过本程序可以了解整个ffmpeg最简单的解码流程。程序为了方便阅读,没有采用面向对象编程。本程序能完成雷霄骅的《基于FFmpeg+SDL的视频播放器的制作——雷霄骅》视频前四小节的内容。
*/
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
}
#include <iostream>
#include <fstream>
using namespace std;int main() {//本地输入的文件路径const char* p_intputFilePath = "sintel.ts";if(p_intputFilePath == NULL) {cout << "请输入文件路径!" << endl;return -1;}//获取文件格式上下文AVFormatContext* p_inptu_file_AVFormatContext = avformat_alloc_context();//打开文件if(avformat_open_input(&p_inptu_file_AVFormatContext, p_intputFilePath, NULL, NULL) != 0) {cout << "文件打开失败" << endl;return -1;};//获取文件流信息if(avformat_find_stream_info(p_inptu_file_AVFormatContext, NULL) < 0) {cout << "获取信息失败" << endl;return -1;}//获取到音频,视频索引int audioIndex = av_find_best_stream(p_inptu_file_AVFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, 0, NULL);int vedioIndex = av_find_best_stream(p_inptu_file_AVFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, 0, NULL);//找到音频流和视频流AVStream* p_input_file_a_AVStream = p_inptu_file_AVFormatContext->streams[audioIndex];AVStream* p_input_file_v_AVStream = p_inptu_file_AVFormatContext->streams[vedioIndex];//获取到解码器AVCodec* p_input_file_a_AVCodec = avcodec_find_decoder(p_input_file_a_AVStream->codecpar->codec_id);AVCodec* p_input_file_v_AVCodec = avcodec_find_decoder(p_input_file_v_AVStream->codecpar->codec_id);//获取音频,视频的AVCodecContext。特别注意,ffmpeg4.2.2版本提倡使用AVCodecParameters。AVCodecContext* p_input_file_a_AVCodecContext = avcodec_alloc_context3(NULL);avcodec_parameters_to_context(p_input_file_a_AVCodecContext, p_input_file_a_AVStream->codecpar);AVCodecContext* p_input_file_v_AVCodecContext = avcodec_alloc_context3(NULL);avcodec_parameters_to_context(p_input_file_v_AVCodecContext, p_input_file_v_AVStream->codecpar);//是否含有视频流和音频流(一般都包含)if(audioIndex < 0) {cout << "此文件不包含音频流或者没有解码器" << endl;}if(vedioIndex < 0) {cout << "此文件不包含视频流或者没有解码器" << endl;}  //打开音频,视频的解码器if(avcodec_open2(p_input_file_a_AVCodecContext, p_input_file_a_AVCodec, NULL) < 0) {cout << "音频解码器打开失败!" << endl; return -1;}if(avcodec_open2(p_input_file_v_AVCodecContext, p_input_file_v_AVCodec, NULL) < 0) {cout << "视频解码器代开失败!" << endl;return -1;}cout << "-------------------------------------- 输出信息开始位置 ---------------------------------" << endl;av_dump_format(p_inptu_file_AVFormatContext, 0, p_intputFilePath, 0);cout << "-------------------------------------- 输出信息结束位置 ---------------------------------" << endl;//读取一帧数据存放空间AVPacket* p_read_frame_AVPacket = av_packet_alloc();//解码一帧数据存放空间AVFrame* p_deco_AVFrame = av_frame_alloc();//转码一帧数据存放空间AVFrame* p_z_p_deco_AVFrame = av_frame_alloc();p_z_p_deco_AVFrame->width = p_input_file_v_AVCodecContext->width;p_z_p_deco_AVFrame->height = p_input_file_v_AVCodecContext->height;p_z_p_deco_AVFrame->format = AV_PIX_FMT_YUV420P;av_frame_get_buffer(p_z_p_deco_AVFrame, 4);//转码格式设置SwsContext* img_convert_ctx = NULL;//视频编码的数据输出到out_file_h264.h264文件ofstream out_file_h264("out_file_h264.h264", ios::binary);//视频解码的数据输出到out_file_yuv240p.yuvofstream out_file_yuv240p("out_file_yuv240p.yuv", ios::binary);//音频编码的数据输出到out_file_aac.pcmofstream out_file_acc("out_file_aac.aac", ios::binary);//音频解码的数据输出到out_file_pcm.pcmofstream out_file_pcm("out_file_pcm.pcm", ios::binary);int re = 0;int v_lenth = p_input_file_v_AVCodecContext->width * p_input_file_v_AVCodecContext->height;while(av_read_frame(p_inptu_file_AVFormatContext, p_read_frame_AVPacket) >= 0) {//输出编码数据if(p_read_frame_AVPacket->stream_index == vedioIndex) {//输出视频编码数据out_file_h264.write((char*) p_read_frame_AVPacket->data, p_read_frame_AVPacket->size);//解码视频re = avcodec_send_packet(p_input_file_v_AVCodecContext, p_read_frame_AVPacket);if(re == 0) {while(avcodec_receive_frame(p_input_file_v_AVCodecContext, p_deco_AVFrame) == 0) {//这里需要转换一下数据 img_convert_ctx = sws_getContext(p_deco_AVFrame->width, p_deco_AVFrame->height, p_input_file_v_AVCodecContext->pix_fmt,p_input_file_v_AVCodecContext->width, p_input_file_v_AVCodecContext->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);sws_scale(img_convert_ctx, p_deco_AVFrame->data, p_deco_AVFrame->linesize, 0, p_input_file_v_AVCodecContext->height,p_z_p_deco_AVFrame->data, p_z_p_deco_AVFrame->linesize);//输出视频解码数据out_file_yuv240p.write((char*) p_z_p_deco_AVFrame->data[0], v_lenth);out_file_yuv240p.write((char*) p_z_p_deco_AVFrame->data[1], v_lenth / 4);out_file_yuv240p.write((char*) p_z_p_deco_AVFrame->data[2], v_lenth / 4);}}else {cout << "视频解解码失败" << endl;break;}}else {//输出音频编码数据out_file_acc.write((char*) p_read_frame_AVPacket->data, p_read_frame_AVPacket->size);//解码音频re = avcodec_send_packet(p_input_file_a_AVCodecContext, p_read_frame_AVPacket);if(re == 0) {while(avcodec_receive_frame(p_input_file_a_AVCodecContext, p_deco_AVFrame) == 0) {//输出音频解码数据for(int i = 0; i < p_deco_AVFrame->nb_samples; i++) {for(int j = 0; j < p_deco_AVFrame->channels; j++) {       out_file_pcm.write((char*) p_deco_AVFrame->data[j], av_get_bytes_per_sample(p_input_file_a_AVCodecContext->sample_fmt));}                         }       }}else {cout << "音频解码失败" << endl;break;}}//减少引用av_packet_unref(p_read_frame_AVPacket);}//释放内存out_file_pcm.close();out_file_acc.close();out_file_yuv240p.close();out_file_h264.close();av_frame_free(&p_z_p_deco_AVFrame);av_frame_free(&p_deco_AVFrame);av_packet_free(&p_read_frame_AVPacket);avcodec_free_context(&p_input_file_a_AVCodecContext);avcodec_free_context(&p_input_file_v_AVCodecContext);avformat_free_context(p_inptu_file_AVFormatContext);

给出观看雷霄骅录制的视频地址:基于FFmpeg+SDL的视频播放器的制作——雷霄骅

使用FFMPEG——4.2.2版本实现提取视频编码解码文件,ffmpeg基础学习。相关推荐

  1. php提取视频中的音频-ffmpeg

    最近有个新需求,其中有一步需要将视频中的音频提取出来,搜了一下ffmpeg可以实现 开发过程中发现windows系统和linux系统不太一样 windows系统配置到环境变量后,不需要注入config ...

  2. FFmpeg入门详解之20:视频编码原理简介

    视频为何需要压缩? 原因:未经压缩的数字视频的数据量巨大 ● 存储困难 ○ 一G只能存储几秒钟的未压缩数字视频. ● 传输困难 ○ 1兆的带宽传输一秒的数字电视视频需要大约4分钟. 主要压缩了什么东西 ...

  3. FFmpeg入门详解之21:视频编码原理的实现

    1.视频编码基础知识 1.1视频和图像和关系 好了,刚才说了图像,现在,我们开始说视频. 所谓视频,大家从小就看动画,都知道视频是怎么来的吧? 没错,大量的图片连续起来,就是视频. 衡量视频,又是用的 ...

  4. shell命令 ffmpeg 批量提取视频的音频文件

    ffmpeg命令提取音频,主要是for循环目录下的文件,判断是否是mp4结尾的文件,然后执行 ffmpeg命令. 下面上命令的代码 #! /bin/bash function rename() {cd ...

  5. 利用ffmpeg进行摄像头提取视频编码为h264通过RTP发送数据到指定的rtp地址

    话不多说命令如下: ffmpeg -f dshow -i video="Logitech QuickCam Easy/Cool" -vcodec libx264 -preset:v ...

  6. ffmpeg:制作gif / 提取视频帧为图片

    1.制作Gif //将指定时间区间的视频转为gif ffmpeg -ss 起始时间 -t 持续时间 -i wangzai.mp4 wangzai.gif ffmpeg -ss 9 -t 5 -i wa ...

  7. 【FFMPEG】各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式

    目录(?)[-] 编解码学习笔记二codec类型 编解码学习笔记三Mpeg系列Mpeg 1和Mpeg 2 编解码学习笔记四Mpeg系列Mpeg 4 编解码学习笔记五Mpeg系列AAC音频 编解码学习笔 ...

  8. 《Android 音视频开发》笔记 - FFmpeg常用命令

    文章目录 FFmpeg简介 命令行工具概述 FFmpeg 处理音视频流程 FFmpeg常用命令 FFmpeg 基本信息查询 FFmpeg 录制 1) Windows上录制音频: 2) Mac 上录制音 ...

  9. 腾讯云+FFmpeg打造一条完备高效的视频产品链

    伴随着飞速增长的视频普及与观看需求,腾讯云技术专家.FFmpeg决策委员会委员赵军认为,视频行业目前存在一个"技术.需求与现实"的三角博弈,其场景犹如带着镣铐的舞蹈,即需要在超高清 ...

最新文章

  1. 像教光学一样在高中教深度学习?怼过LeCun的Google大牛认为这事有出路
  2. 你有没有成为技术作家的潜力
  3. (原创)VS2017 C# 运行 Javasrcipt RSA 加密用户名登录 Java开发的服务器
  4. 【ARM】ARM汇编程序设计(六) stm和ldm
  5. 零基础入门stm32需要学这些东西
  6. Getting started with Processing 第七章总结
  7. python调用程序压缩文件_Python在后台自动解压各种压缩文件的实现方法
  8. 常用webservice网址
  9. 六、小程序|App抓包-移动端抓包app-抓包
  10. 炸裂!跑P站上教微积分,年入170w...
  11. EXCEL自定义功能区Ribbon
  12. linux设置mysql开机启动
  13. c语言解除键盘锁定,解除键盘锁定,详细教您笔记本解除键盘锁定
  14. Volley读取文档和图片
  15. 内核层读写应用层文件,使用filp_open函数。
  16. PYTHON对数值变量进行标准化,离散变量标签化
  17. 实时高分辨率视频抠像
  18. mysql表格时间函数大全_mysql汇总数据函数
  19. 利用先进先出原则统计易飞ERP呆滞库存
  20. stm32中cubmx+keil+proteus+虚拟串口+串口助手的使用

热门文章

  1. java quartz 是干什么的_Quartz可以用来做什么
  2. Vue纯零基础教学第三天--到走入Vue项目实际开发的内心深处
  3. 400Gbps 网络面临的挑战
  4. 2.5元组tuple
  5. PIC单片机之PWM PWM原理
  6. 安装RapidDesign_v1.3.0.Cracked.DX10.3.Rio
  7. 使用图像播放Java中的一种技巧-搜索图像,将图像转换为文本,隐藏数据
  8. 把全球大前端技术 ppt 分享给大家
  9. 小车加速减速的c语言,c2控制速度技巧
  10. Jquery弹出层,背景变暗 居中