嵌入式实践教程--FFmpeg中H264裸流解码为YUV420P原像素

简介: 嵌入式实践教程--FFmpeg中H264裸流解码为YUV420P原像素

一、流程图



image.png

image.png


二、代码



#include <iostream>
using namespace std;
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include<libavutil\imgutils.h>
#include <libavfilter/avfilter.h>
#include <libswscale/swscale.h>
}
AVFormatContext* AFCtx_p;//解封装上下文
AVCodecContext* ACCtx_p;//解码器上下文
AVCodec* codec_p;//解码器
AVFrame* pFrame;
AVFrame* pFrameyuv;
AVPacket* packet;
struct SwsContext* img_convert_ctx;
int videoindex = -1;
int ret, got_picture = 0;
int y_size;
const char path[] = "./res/5min.h264";
int main(int argc, char* argv[])
{
  //打开H264文件,将文件信息存入解封装上下文
  if (avformat_open_input(&AFCtx_p, path, NULL, NULL) != 0)
  {
  cout << "open failed\n" << endl;
  return -1;
  }
  //寻找视频流信息
  if (avformat_find_stream_info(AFCtx_p, NULL) < 0)
  {
  cout << "dtream find failed\n" << endl;
  return -1;
  }
  //dump调试信息
  av_dump_format(AFCtx_p, -1, path, NULL);
  //打开视频并且获取了视频流,设置视频索引默认值
  for (int i = 0; i<AFCtx_p->nb_streams; i++)
  {
  if (AFCtx_p->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
  {
    videoindex = i;
  }
  }
  //如果没有找到视频索引,说明不是一个视频文件
  if (videoindex == -1)
  {
  cout << "not a video\n" << endl;
  return -1;
  }
  //分配解码器上下文空间
  ACCtx_p = avcodec_alloc_context3(NULL);
  //获取编解码器上下文信息
  if (avcodec_parameters_to_context(ACCtx_p, AFCtx_p->streams[videoindex]->codecpar) < 0)
  {
  cout << "copy stream failed\n" << endl;
  return -1;
  }
  //查找解码器
  codec_p = avcodec_find_decoder(ACCtx_p->codec_id);
  if (!codec_p)
  {
  cout << "find decoder error\n" << endl;
  return -1;
  }
  //打开解码器
  if (avcodec_open2(ACCtx_p, codec_p, NULL) != 0)
  {
  cout << "open codec failed" << endl;
  return -1;
  }
  //裁剪图像
  img_convert_ctx = sws_getContext(ACCtx_p->width, ACCtx_p->height,
  ACCtx_p->pix_fmt,
  ACCtx_p->width, ACCtx_p->height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);
  if (!img_convert_ctx)
  {
  cout << "get swscale context failed\n" << endl;
  return -1;
  }
  packet = av_packet_alloc();
  pFrame = av_frame_alloc();
  pFrameyuv = av_frame_alloc();
  //获取转换后YUV数据的大小
  int video_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, ACCtx_p->width,
  ACCtx_p->height, 1);
  uint8_t* buf = (uint8_t*)av_malloc(video_size);
  av_image_fill_arrays(pFrameyuv->data, pFrameyuv->linesize,
  buf, AV_PIX_FMT_YUV420P, ACCtx_p->width, ACCtx_p->height, 1);
  char errbuf[256] = { 0 };
  FILE* fp_yuv = fopen("out.yuv", "wb+");
  //循环读取帧数据并转换写入
  while (av_read_frame(AFCtx_p, packet) >= 0)
  {
  if (packet->stream_index == videoindex)
  {
    if (avcodec_send_packet(ACCtx_p, packet) != 0)
    {
    cout << "send video stream packet failed\n" << endl;
    return -1;
    }
    if (avcodec_receive_frame(ACCtx_p, pFrame) != 0)
    {
    cout << "receive video frame failed\n" << endl;
    return -1;
    }
    cout << "decoding frame" << ACCtx_p->frame_number << endl;
    sws_scale(img_convert_ctx,
    pFrame->data, pFrame->linesize,
    0, ACCtx_p->height, pFrameyuv->data, pFrameyuv->linesize);
    y_size = ACCtx_p->width * ACCtx_p->height;
    fwrite(pFrameyuv->data[0], 1, y_size, fp_yuv);//Y
    fwrite(pFrameyuv->data[1], 1, y_size/4, fp_yuv);//U
    fwrite(pFrameyuv->data[2], 1, y_size/4, fp_yuv);//V
  }
  }
  fclose(fp_yuv);
  av_free(buf);
  av_frame_free(&pFrame);
  av_frame_free(&pFrameyuv);
  av_packet_free(&packet);
  sws_freeContext(img_convert_ctx);
  avcodec_free_context(&ACCtx_p);
  avformat_close_input(&AFCtx_p);
  avformat_free_context(AFCtx_p);
  return 1;
}


相关文章
|
7月前
|
算法 数据处理 开发者
FFmpeg库的使用与深度解析:解码音频流流程
FFmpeg库的使用与深度解析:解码音频流流程
124 0
|
5月前
|
数据采集 大数据 Python
FFmpeg 在爬虫中的应用案例:流数据解码详解
在大数据背景下,网络爬虫与FFmpeg结合,高效采集小红书短视频。需准备FFmpeg、Python及库如Requests和BeautifulSoup。通过设置User-Agent、Cookie及代理IP增强隐蔽性,解析HTML提取视频链接,利用FFmpeg下载并解码视频流。示例代码展示完整流程,强调代理IP对避免封禁的关键作用,助你掌握视频数据采集技巧。
FFmpeg 在爬虫中的应用案例:流数据解码详解
|
5月前
|
语音技术 C语言 Windows
语音识别------ffmpeg的使用01,ffmpeg的安装,会做PPT很好,ffmpeg不具备直接使用,只可以操作解码数据,ffmpeg用C语言写的,得学C语言,ffmpeg的安装
语音识别------ffmpeg的使用01,ffmpeg的安装,会做PPT很好,ffmpeg不具备直接使用,只可以操作解码数据,ffmpeg用C语言写的,得学C语言,ffmpeg的安装
|
6月前
|
Linux 编解码 Python
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
AV1是一种高效免费的视频编码标准,由AOM联盟制定,相比H.265压缩率提升约27%。各大流媒体平台倾向使用AV1。本文介绍了如何在Linux环境下为FFmpeg集成AV1编解码库libaom、libdav1d和libsvtav1。涉及下载源码、配置、编译和安装步骤,包括设置环境变量以启用这三个库。
305 3
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
|
6月前
|
编解码 Linux 计算机视觉
python 调用ffmpeg使用usb摄像头录制视频,输出h264格式,自动获取摄像头的最佳帧率和最大画面尺寸
使用 Python 调用 FFmpeg 进行 USB 摄像头视频录制,需先确保安装 FFmpeg 和 Python 的 `subprocess` 模块。代码示例展示了如何自动获取摄像头的最佳帧率和最大分辨率,然后录制视频。首先通过 FFmpeg 列出摄像头格式获取信息,解析出帧率和分辨率,选择最优值。之后调用 FFmpeg 命令录制视频,设置帧率、分辨率等参数。注意 `/dev/video0` 是 Linux 的摄像头设备路径,Windows 系统需相应调整。代码中未直接实现自动获取最佳参数,通常需要借助其他库如 OpenCV。
|
7月前
|
编解码 5G Linux
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
AVS3是中国首个8K及5G视频编码标准,相比AVS2和HEVC性能提升约30%。解码器libuavs3d支持8K/60P视频实时解码,兼容多种平台。《FFmpeg开发实战》书中介绍了在Windows环境下如何集成libuavs3d到FFmpeg。集成步骤包括下载源码、使用Visual Studio 2022编译、调整配置、安装库文件和头文件,以及重新配置和编译FFmpeg以启用libuavs3d。
121 0
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
|
7月前
|
编解码 Linux 5G
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
AVS3,中国制定的第三代音视频标准,是首个针对8K和5G的视频编码标准,相比AVS2和HEVC性能提升约30%。uavs3d是AVS3的解码器,支持8K/60P实时解码,且在各平台有优秀表现。要为FFmpeg集成AVS3解码器libuavs3d,需从GitHub下载最新源码,解压后配置、编译和安装。之后,重新配置FFmpeg,启用libuavs3d并编译安装,通过`ffmpeg -version`确认成功集成。
134 0
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
|
7月前
|
存储 缓存 调度
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
《FFmpeg开发实战》第10章示例playsync.c在处理音频流和视频流交错的文件时能实现同步播放,但对于分开存储的格式,会出现先播放全部声音再快速播放视频的问题。为解决此问题,需改造程序,增加音频处理线程和队列,以及相关锁,先将音视频帧读入缓存,再按时间戳播放。改造包括声明新变量、初始化线程和锁、修改数据包处理方式等。代码修改后在playsync2.c中,编译运行成功,控制台显示日志,SDL窗口播放视频并同步音频,证明改造有效。
131 0
FFmpeg开发笔记(十九)FFmpeg开启两个线程分别解码音视频
|
7月前
|
存储 编解码 编译器
FFmpeg 7.0 正式登场:全新 VVC 解码器
【4月更文挑战第9天】最新版本的流行视频处理软件FFmpeg 7.0,代号为“Dijkstra”,已正式发布。
246 0
|
7月前
|
存储 算法 编译器
【ffmpeg 到Qt的图片格式转换】精彩的像素:深入解析 AVFrame 到 QImage 的转换
【ffmpeg 到Qt的图片格式转换】精彩的像素:深入解析 AVFrame 到 QImage 的转换
275 0