ffmpeg hevc_ffmpeg视频解码

ffmpeg hevc_ffmpeg视频解码本次目标:1)将容器中的音频码流和视频码流分离出来。2)针对mp4文件中的码流情况进行修复。解封装的基本过程:#include<stdio.h>#include”libavcodec/avcodec.h”#include”libavformat/avformat.h”//MPEG-TS文件解封装得到的码流可播放,MP4解封装得到的码流不可播放;//这与容器的封装方式有关。voiddemuxer(constchar*url){//初始化格式上下文

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

本次目标:

1)将容器中的音频码流和视频码流分离出来。

2)针对mp4文件中的码流情况进行修复。

解封装的基本过程:

#include <stdio.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"

// MPEG-TS文件解封装得到的码流可直接播放
// MP4/FLV/MKV解封装得到的码流不可播放;
// 这与容器的封装方式有关。
void demuxer(const char *url) {
    // 初始化格式上下文
    AVFormatContext *fmt_ctx = avformat_alloc_context();
    if (fmt_ctx == NULL) {
        printf("failed to alloc format context\n");
        goto _Error;
    }

    // 打开输入流
    if (avformat_open_input(&fmt_ctx, url, NULL, NULL) < 0) {
        printf("failed to open input url\n");
        goto _Error;
    }

    // 读取媒体文件信息
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        printf("failed to find stream\n");
        goto _Error;
    }
    av_dump_format(fmt_ctx, 0, url, 0);


    // 寻找音频流和视频流下标
    int video_index = -1, audio_index = -1;
    for (int i = 0; i < fmt_ctx->nb_streams; i++) {
        if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_index = i;
        } else if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            audio_index = i;
        }
    }
    if (video_index < 0 || audio_index < 0) {
        printf("failed to find stream index\n");
        goto _Error;
    }

    // 由打印的视频文件信息确定码流类型
    char audiofile[128], videofile[128];
    printf("type the name of output audiofile:");
    scanf("%s", audiofile);
    printf("\ntype the name of output videofile:");
    scanf("%s", videofile);
    FILE *faudio = fopen(audiofile, "w+");
    FILE *fvideo = fopen(videofile, "w+");
    AVPacket *packet = av_packet_alloc();

    while (av_read_frame(fmt_ctx, packet) == 0) {

        if (packet->stream_index == audio_index) {
            fwrite(packet->data, 1, packet->size, faudio);
        }
        else if (packet->stream_index == video_index) {
            fwrite(packet->data, 1, packet->size, fvideo);
        }
        av_packet_unref(packet);
    }

_Error:
    if (fmt_ctx) avformat_close_input(&fmt_ctx);
    if (faudio)  fclose(faudio);
    if (fvideo)  fclose(fvideo);
    if (packet)  av_packet_free(&packet);
}


int main(int argc, char const* argv[])
{
    demuxer(argv[1]);
    return 0;
}

编译测试:得到视频信息后,根据文件中的编码信息(mp3或aac,h264或mpeg4,mpeg4码流文件后辍为.m4v),命名解封装的码流文件。
image-20210514113830833

mp4文件解封装得到的h264码流和aac码流都不能解码播放!

1、mp4文件中的码流有什么不同

	Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 
	640x352, 748 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
	
	Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 
	44100 Hz, stereo, fltp, 128 kb/s (default)

MP4封装格式是基于QuickTime容器格式定义,媒体描述与媒体数据分开。从MP4得到的H264和AAC码流是ES流,它们缺失解码时必要的起始码/SPS/PPSadts头

我们常规的H264帧数据保存格式是annexb,是具有起始码0x000001或0x00000001;mpeg-ts文件中保存的是视频码流是存在起始码的,而在mp4文件中没有起始码。

H.264视频编码格式主要分为两种形式,即带起始码的H.264码流不带起始码的H.264码流,其中,前者就是我们比较熟悉的H264、X264;后者就是指AVC1

More:MP4中的H264和AAC

2、怎么修复MP4中的码流?

AAC码流(mp4a):保存一帧码流数据前,补充相应的adts头;

H264码流(avc1):使用h264_mp4toannexb过滤器,对视频码流进行处理。

①每一帧前补充ADTS头

// 生成7字节的ADTS头
char *adts_header_gen(int len) {
    static char header[7];

    int profile = 2;    // AAC LC
    int freqidx = 4;    // 3 - 48k, 4 - 44.1k 
    int chncfg  = 2;    // 声道数量 

    header[0] = 0xFF;
    header[1] = 0xF1;
    header[2] = ((profile-1) << 6) | (freqidx << 2) | (chncfg >> 2);
    header[3] = ((chncfg & 3) << 6)| (len >> 11);
    header[4] = (len & 0x7FF) >> 3;
    header[5] = ((len & 0x7) << 5) | 0x1F;
    header[6] = 0xFC;
    return header;
}
if (packet->stream_index == audio_index) {
	// packet->size是adts中数据块的长度
	fwrite(adts_header_gen(packet->size+7), 1, 7, faudio);
	fwrite(packet->data, 1, packet->size, faudio);
}

More:AAC音频码流解析

②使用h264_mp4toannexb过滤器处理h264码流

// 初始化过滤器
const AVBitStreamFilter *bsf = av_bsf_get_by_name("h264_mp4toannexb");
if (bsf == NULL) {
	printf("failed to find stream filter\n");
	goto _Error;
}
AVBSFContext *bsf_ctx;
av_bsf_alloc(bsf, &bsf_ctx);
avcodec_parameters_copy(bsf_ctx->par_in, fmt_ctx->streams[video_index]->codecpar);
av_bsf_init(bsf_ctx);
else if (packet->stream_index == video_index) {
    if (av_bsf_send_packet(bsf_ctx, packet) == 0) {
        while (av_bsf_receive_packet(bsf_ctx, packet) == 0) {
            fwrite(packet->data, 1, packet->size, fvideo);
        }
    }
}

经过比特流过滤器的处理,每个AVPacket的data添加了H.264的NALU的起始码{0,0,0,1};每个IDR帧数据前面添加了SPS和PPS。

More:解析h264视频码流

视频播放效果:

原mp4文件:
image-20210514112106240

out.h264码流文件:
image-20210514112149236

out.aac文件:
image-20210514112333031

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/181225.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • excel变成xml格式_XML文件

    excel变成xml格式_XML文件最近做了一个小工具,可以将XML和Excel之前互转。里面用到的XML读写库是tinyxml,在Excel2010上运行,请先确保装了Excel,而不是WPS。代码写的比较挫,一大坨,最近忙也懒得去做优化了。github地址:XML与Excel互转工具目前只支持ANSI格式的Excel文件与ANSI格式的XML文件互转。由于在写的时候,里面的存储方式都是CString,默认为ANS

    2022年8月22日
    6
  • 【JS字符串方法】JS字符串方法

    【JS字符串方法】JS字符串方法字符串的 ES5 和 ES6 方法 ES5String fromCharCode 该方法的参数是一系列 Unicode 码点 返回对应的字符串 charAt 该方法返回指定位置的字符 参数是从 0 开始编号的位置 charCodeAt 方法返回给定位置字符的 Unicode 码点 十进制表示 相当于 String fromCharCode 的逆操作 concat 方法用于连

    2025年10月28日
    3
  • 消息队列 能做成 websocket 那样推送消息到客户端吗

    消息队列 能做成 websocket 那样推送消息到客户端吗

    2022年2月10日
    41
  • 蓝桥杯单片机必备知识—–(3)pcf8591–ADC

    蓝桥杯单片机必备知识—–(3)pcf8591–ADC

    2021年4月13日
    321
  • ES安装教程详解_wampserver安装教程

    ES安装教程详解_wampserver安装教程0.安装前准备 centos7+ java8+ elastic6.2.4+2.在官方网站下载ESwgethttp://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.4.1.tar.gz3.安装JDK(必须JDK1.8+)rpm-ivhjdk-8u181-linux-x64.rpm /*注意:默认安装位置/usr/java/jdk1.8.0_171-amd64*/4.配置环境变量vi

    2022年4月19日
    112
  • epoch和batchsize设置多大(BatchDataset)

    梯度下降  这是一个在机器学习中用于寻找最佳结果(曲线的最小值)的迭代优化算法。  梯度的含义是斜率或者斜坡的倾斜度。  下降的含义是代价函数的下降。  算法是迭代的,意思是需要多次使用算法获取结果,以得到最优化结果。在数据很庞大的时候(在机器学习中,几乎任何时候都是),我们才需要使用epochs,batchsize,迭代这些术语,在这种情况下,一次性将数据输入计算机是不可能的…

    2022年4月15日
    551

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号