解码AVC(h264)裸流为yuv420P写入文件

2024-04-09 16:12

本文主要是介绍解码AVC(h264)裸流为yuv420P写入文件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

使用AVC裸流解析器解析AVC裸流文件,然后解码为yuv420P格式写入文件

// 解码h264
#include "myLog.h"
#include <iostream>extern "C"
{
#include "libavcodec\avcodec.h"
}#define VIDEO_INBUF_SIZE 20480		// 最初读取数据大小
#define VIDEO_REFILL_THRESH 4096static char* av_get_err(int errnum)
{char err_buf[128] = { 0 };av_strerror(errnum, err_buf, 128);return err_buf;
}static void print_video_format(const AVFrame *frame)
{printf("width: %u\n", frame->width);printf("height: %u\n", frame->height);printf("format: %u\n", frame->format);
}static void decode_video(AVCodecContext* dec_ctx, AVPacket* pkt, AVFrame* frame, FILE* out_fp)
{int nRet = avcodec_send_packet(dec_ctx, pkt);if (nRet == AVERROR(EAGAIN)){LOG_WARNING("need more pkt\n");return;}else if (nRet < 0){LOG_WARNING("Error submitting the packet to the decoder, err:%s, pkt_size:%d\n",av_get_err(nRet), pkt->size);return;}// 一个pkt可能会有多个framewhile (nRet >= 0){nRet = avcodec_receive_frame(dec_ctx, frame);if (nRet == AVERROR(EAGAIN) || nRet == AVERROR_EOF){return;}else if (nRet < 0){LOG_WARNING("Error during decoding\n");return;}// 打印一次信息static bool is_print = false;if (!is_print){is_print = !is_print;print_video_format(frame);}// 一般H264默认为 AV_PIX_FMT_YUV420P// linesize[i]代表每行的字节数量,所以每行的偏移是linesize[i]// 写入YUV420P格式数据(每次写入一行数据)for (int i = 0; i < frame->height; i++)	// Y{fwrite(frame->data[0] + i * frame->linesize[0], 1, frame->width, out_fp);}for (int i = 0; i < frame->height / 2; i++)	// U{fwrite(frame->data[1] + i * frame->linesize[1], 1, frame->width / 2, out_fp);}for (int i = 0; i < frame->height / 2; i++)	// V{fwrite(frame->data[2] + i * frame->linesize[2], 1, frame->width / 2, out_fp);}}
}// ffplay  -f rawvideo -pixel_format yuv420p -video_size 852x480 -i HTA_10s_420P.yuv
int main_video_decodec()
{const char* in_file = "./HTA_10s.h264";const char* out_file = "./HTA_10s_420P.yuv";// 1. 直接查找h264解码器AVCodec* video_dec = avcodec_find_decoder(AV_CODEC_ID_H264);if (video_dec == nullptr){LOG_WARNING("avcodec_find_decoder error\n");return -1;}// 2. 创建解码器上下文AVCodecContext* dec_ctx = avcodec_alloc_context3(video_dec);if (dec_ctx == nullptr){LOG_WARNING("avcodec_alloc_context3 error\n");return -2;}// 3. 初始化(h264)裸流解析器AVCodecParserContext* parser_ctx = av_parser_init(dec_ctx->codec_id);if (parser_ctx == nullptr){LOG_WARNING("av_parser_init error\n");return -3;}// 4. 将解码器与上下文关联int nRet = avcodec_open2(dec_ctx, video_dec, NULL);if (nRet < 0){LOG_WARNING("avcodec_open2 error\n");return -4;}// 5. 打开输入输出文件FILE* in_fp = fopen(in_file, "rb");if (nullptr == in_fp){LOG_WARNING("open in_file error\n");return -5;}FILE* out_fp = fopen(out_file, "wb");if (nullptr == out_fp){LOG_WARNING("open out_file error\n");return -6;}// 读取文件开始解码uint8_t inbuf[VIDEO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];uint8_t *data = inbuf;size_t   data_size = 0;data_size = fread(inbuf, 1, VIDEO_INBUF_SIZE, in_fp);AVPacket* pkt = av_packet_alloc();AVFrame* frame = av_frame_alloc();while (data_size > 0){if (frame == nullptr){LOG_WARNING("frame is nullptr\n");return -7;}nRet = av_parser_parse2(parser_ctx, dec_ctx, &pkt->data, &pkt->size,data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);if (nRet < 0){LOG_WARNING("av_parser_parse2 error\n");return -8;}data += nRet;data_size -= nRet;if (pkt->size){// 解码decode_video(dec_ctx, pkt, frame, out_fp);}if (data_size < VIDEO_REFILL_THRESH){memmove(inbuf, data, data_size);data = inbuf;int len = fread(inbuf + data_size, 1, VIDEO_INBUF_SIZE - data_size, in_fp);if (len > 0){data_size += len;}}}// 冲刷解码器pkt->data = NULL;pkt->size = 0;decode_video(dec_ctx, pkt, frame, out_fp);// 释放资源fclose(in_fp);fclose(out_fp);avcodec_free_context(&dec_ctx);av_parser_close(parser_ctx);av_frame_free(&frame);av_packet_free(&pkt);getchar();return 0;
}

这篇关于解码AVC(h264)裸流为yuv420P写入文件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/888625

相关文章

通过C#和RTSPClient实现简易音视频解码功能

《通过C#和RTSPClient实现简易音视频解码功能》在多媒体应用中,实时传输协议(RTSP)用于流媒体服务,特别是音视频监控系统,通过C#和RTSPClient库,可以轻松实现简易的音视... 目录前言正文关键特性解决方案实现步骤示例代码总结最后前言在多媒体应用中,实时传输协议(RTSP)用于流媒体服

FFmpeg系列-视频解码后保存帧图片为ppm

在正常开发中遇到花屏时怎么处理呢?可以把解码后的数据直接保存成帧图片保存起来,然后直接看图片有没有花屏来排除是否是显示的问题,如果花屏,则代表显示无问题,如果图片中没有花屏,则可以往显示的方向去排查了。 void saveFrame(AVFrame* pFrame, int width, int height, int iFrame){FILE *pFile;char szFilename[

Android/Linux 磁盘写入缓存/等待时间 参数修改

Linux系统当进行文件写操作时,并不会将数据立马写入磁盘,而是写写到缓存,等待达到占用内存一定比例或超过一定时间才会批量将这些缓存数据写入磁盘,这样可以减少IO操作,提升性能和磁盘寿命。如果数据还没来得及写入磁盘发生硬件掉电,这些数据就会丢失。应用可以调用sync实时将内容写入磁盘避免丢失。排查丢失问题可以在断电前执行sync命令,看能不能复现,若无法复现,说明就是缓存没有及时写入磁盘导致。

python读取pdf内容写入到Excel表格中

要从每个 PDF 文件中提取全文内容,并将这些内容粘贴到一个新的或现有的表格中,你可以使用 Python 的库来完成这一任务。以下是一个简化的步骤和示例代码,展示如何实现这个过程。 步骤概述 读取文件夹中的所有 PDF 文件。提取每个 PDF 文件的全文内容。创建一个新的 Excel 表格或使用现有的表格。将提取的内容粘贴到表格中,每个 PDF 的内容放在一个垂直单元格中。保存表格文件。 所

C++利用jsoncpp库实现写入和读取json文件(含中文处理)

C++利用jsoncpp库实现写入和读取json文件 1 jsoncpp常用类1.1 Json::Value1.2 Json::Reader1.3 Json::Writer 2 json文件3 写json文件3.1 linux存储结果3.2 windows存储结果 3 读json文件4 读json字符串参考文章 在C++中使用跨平台的开源库JsonCpp,实现json的序列化和反序列

【Hot100】LeetCode—394. 字符串解码

目录 1- 思路栈实现+四种情况处理 2- 实现⭐394. 字符串解码——题解思路 3- ACM 实现 原题链接:394. 字符串解码 1- 思路 栈实现+四种情况处理 ① 遇到数字,进行倍数相加 、②遇到左括号,压栈之前的元素、③遇到右括号弹出,栈进行拼接、④否则遇到字母,直接拼接在 res通过栈,实现先进后出的思想 对于输入 3[a2[c]] 的输入,在读到 3[得

libmad音频解码库-Linux交叉编译移植

下载并解压libmad-0.15.1b.tar.gz 下载链接:https://downloads.sourceforge.net/mad/libmad-0.15.1b.tar.gz $tar -xvf libmad-0.15.1b.tar.gz$cd libmad-0.15.1b 1、先执行下面的命令:这条命令是为了适配高版本的gcc,因为高版本的gcc已经将-fforce-mem去除了:

包拯断案 | 数据库从库GTID在变化 为何没有数据写入@还故障一个真相

提问:作为DBA运维的你是否遇到过这些烦恼 1、数据库从库复制链路如何正确配置表过滤信息? 2、数据库从库的GTID在变化,实际却没有数据写入,究竟是什么原因? 心中有章,遇事不慌 作为DBA的你,遇到问题无从下手,除了在问题面前徘徊,还能如何选择?如果你一次或多次遇到该问题还是 无法解决,又很懊恼,该如何排忧呢?关注公众号,关注《包拯断案》专栏,让小编为你排忧解难~ #包拯秘籍#

Flink读取kafka数据并以parquet格式写入HDFS

《2021年最新版大数据面试题全面开启更新》 《2021年最新版大数据面试题全面开启更新》 大数据业务场景中,经常有一种场景:外部数据发送到kafka中,flink作为中间件消费kafka数据并进行业务处理;处理完成之后的数据可能还需要写入到数据库或者文件系统中,比如写入hdfs中; 目前基于spark进行计算比较主流,需要读取hdfs上的数据,可以通过读取parquet:spark.read

Java读取/写入Yaml配置文件

JYaml文件流读取/写入Yaml配置文件 yaml配置文件格式规范:- 表示sequence(list列表结构),: 表示map键值对 #以下是示例yaml结构age: 23children: - age: 8name: mary1sex: man- age: 9name: simon2sex: fatelname: simon.zhangsex: man 1.准备工作,创建