FFmpeg--mp4解封装为aac和h264

2024-03-11 16:20
文章标签 封装 ffmpeg mp4 h264 aac

本文主要是介绍FFmpeg--mp4解封装为aac和h264,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

mp4文件解封装:

视频文件(mp4 )–解封装—音频流(aac ), 视频流 (h264)

流程

请添加图片描述

code

命令行参数: input.mp4 out.h264 out.aac

#include <stdio.h>#include "libavutil/log.h"
#include "libavformat/avformat.h"#define ERROR_STRING_SIZE 1024#define ADTS_HEADER_LEN  7;int adts_header(char * const p_adts_header, const int data_length,const int profile, const int samplerate,const int channels)
{}int main(int argc, char **argv)
{char *in_filename = argv[1];char *h264_filename = argv[2];char *aac_filename = argv[3];FILE *aac_fd = NULL;FILE *h264_fd = NULL;h264_fd = fopen(h264_filename, "wb");if(!h264_fd) {printf("fopen %s failed\n", h264_filename);return -1;}aac_fd = fopen(aac_filename, "wb");if(!aac_fd) {printf("fopen %s failed\n", aac_filename);return -1;}AVFormatContext *ifmt_ctx = NULL;int video_index = -1;int audio_index = -1;AVPacket *pkt = NULL;int ret = 0;char errors[ERROR_STRING_SIZE+1];  // 主要是用来缓存解析FFmpeg api返回值的错误stringifmt_ctx = avformat_alloc_context();if(!ifmt_ctx) {printf("avformat_alloc_context failed\n");//        fclose(aac_fd);return -1;}ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL);if(ret < 0) {av_strerror(ret, errors, ERROR_STRING_SIZE);avformat_close_input(&ifmt_ctx);return -1;}video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if(video_index == -1) {avformat_close_input(&ifmt_ctx);return -1;}audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if(audio_index == -1) {avformat_close_input(&ifmt_ctx);return -1;}// h264_mp4toannexbconst AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb");      // 对应面向对象的方法if(!bsfilter) {avformat_close_input(&ifmt_ctx);return -1;}AVBSFContext *bsf_ctx = NULL;        // 对应面向对象的变量ret = av_bsf_alloc(bsfilter, &bsf_ctx);if(ret < 0) {av_strerror(ret, errors, ERROR_STRING_SIZE);avformat_close_input(&ifmt_ctx);return -1;}ret = avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[video_index]->codecpar);if(ret < 0) {av_strerror(ret, errors, ERROR_STRING_SIZE);avformat_close_input(&ifmt_ctx);av_bsf_free(&bsf_ctx);return -1;}ret = av_bsf_init(bsf_ctx);if(ret < 0) {av_strerror(ret, errors, ERROR_STRING_SIZE);avformat_close_input(&ifmt_ctx);av_bsf_free(&bsf_ctx);return -1;}pkt = av_packet_alloc();av_init_packet(pkt);while (1) {ret = av_read_frame(ifmt_ctx, pkt);     // 不会去释放pkt的buf,如果我们外部不去释放,就会出现内存泄露if(ret < 0 ) {av_strerror(ret, errors, ERROR_STRING_SIZE);printf("av_read_frame failed:%s\n", errors);break;}// av_read_frame 成功读取到packet,则外部需要进行buf释放// 处理视频  mp4的视频流不带startcode  h264格式带,需加上if(pkt->stream_index == video_index) {// 处理视频ret = av_bsf_send_packet(bsf_ctx, pkt); if(ret < 0) {      av_strerror(ret, errors, ERROR_STRING_SIZE);av_packet_unref(pkt);continue;}while (1) {ret = av_bsf_receive_packet(bsf_ctx, pkt);if(ret != 0) {break;}size_t size = fwrite(pkt->data, 1, pkt->size, h264_fd);if(size != pkt->size){av_log(NULL, AV_LOG_DEBUG, "h264 warning, length of writed data isn't equal pkt->size(%d, %d)\n",size,pkt->size);}av_packet_unref(pkt);}} else if(pkt->stream_index == audio_index) {// 处理音频char adts_header_buf[7] = {0};adts_header(adts_header_buf, pkt->size,ifmt_ctx->streams[audio_index]->codecpar->profile,ifmt_ctx->streams[audio_index]->codecpar->sample_rate,ifmt_ctx->streams[audio_index]->codecpar->channels);fwrite(adts_header_buf, 1, 7, aac_fd); size_t size  fwrite(pkt->data, 1, pkt->size, aac_fd);= ;   // 写adts dataif(size != pkt->size){av_log(NULL, AV_LOG_DEBUG, "aac warning, length of writed data isn't equal pkt->size(%d, %d)\n",size,pkt->size);}av_packet_unref(pkt);} else {av_packet_unref(pkt);       // 释放buffer}}printf("while finish\n");
failed:if(h264_fd) {fclose(h264_fd);}if(aac_fd) {fclose(aac_fd);}if(pkt)av_packet_free(&pkt);if(ifmt_ctx)avformat_close_input(&ifmt_ctx);printf("Hello World!\n");return 0;
}

debug:
测试音频流是否加上startcode
1 av_bsf_send_packet(bfs_ctx,pkt);
pkt: data
查看 Memory: 00 00 02 b0
2 fwrite(pkt->data,pkt->size,h264_fd);
pkt->data:
Memory: 00 00 00 01 (startcode)

这篇关于FFmpeg--mp4解封装为aac和h264的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Python使用FFmpeg实现高效音频格式转换工具

《Python使用FFmpeg实现高效音频格式转换工具》在数字音频处理领域,音频格式转换是一项基础但至关重要的功能,本文主要为大家介绍了Python如何使用FFmpeg实现强大功能的图形化音频转换工具... 目录概述功能详解软件效果展示主界面布局转换过程截图完成提示开发步骤详解1. 环境准备2. 项目功能结

SpringBoot使用ffmpeg实现视频压缩

《SpringBoot使用ffmpeg实现视频压缩》FFmpeg是一个开源的跨平台多媒体处理工具集,用于录制,转换,编辑和流式传输音频和视频,本文将使用ffmpeg实现视频压缩功能,有需要的可以参考... 目录核心功能1.格式转换2.编解码3.音视频处理4.流媒体支持5.滤镜(Filter)安装配置linu

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

一文详解如何在Vue3中封装API请求

《一文详解如何在Vue3中封装API请求》在现代前端开发中,API请求是不可避免的一部分,尤其是与后端交互时,下面我们来看看如何在Vue3项目中封装API请求,让你在实现功能时更加高效吧... 目录为什么要封装API请求1. vue 3项目结构2. 安装axIOS3. 创建API封装模块4. 封装API请求

鸿蒙中Axios数据请求的封装和配置方法

《鸿蒙中Axios数据请求的封装和配置方法》:本文主要介绍鸿蒙中Axios数据请求的封装和配置方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.配置权限 应用级权限和系统级权限2.配置网络请求的代码3.下载在Entry中 下载AxIOS4.封装Htt

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

SpringBoot中封装Cors自动配置方式

《SpringBoot中封装Cors自动配置方式》:本文主要介绍SpringBoot中封装Cors自动配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot封装Cors自动配置背景实现步骤1. 创建 GlobalCorsProperties

Java导入、导出excel用法步骤保姆级教程(附封装好的工具类)

《Java导入、导出excel用法步骤保姆级教程(附封装好的工具类)》:本文主要介绍Java导入、导出excel的相关资料,讲解了使用Java和ApachePOI库将数据导出为Excel文件,包括... 目录前言一、引入Apache POI依赖二、用法&步骤2.1 创建Excel的元素2.3 样式和字体2.

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表