5、MP4解复用---AAC+H264

  • MP4
    MP4同样是一种容器格式,是由一个一个Box组成,每个Box又分为Header与Data,Data又包含很多子Box,具体的MP4文件结构也看过,内部Box结构比较复杂,一般不写MP4解释器的话,Box结构不用了解太细,对MP4封装有MP4V2库可以使用,当然也可以使用FFMPEG库。
    本文从代码的角度上来分析使用FFMPEG对MP4文件解复用。
    完整代码如下:
bash 复制代码
#include <stdio.h>

#include "libavutil/log.h"
#include "libavformat/avformat.h"

#define ERROR_STRING_SIZE 1024

#define ADTS_HEADER_LEN  7;

const int sampling_frequencies[] = {
    96000,
    88200,
    64000,
    48000,
    44100,
    32000,
    24000,
    22050,
    16000,
    12000,
    11025,
    8000
};

int adts_header(char * const p_adts_header, const int data_length,
                const int profile, const int samplerate,
                const int channels)
{

    int sampling_frequency_index = 3;
    int adtsLen = data_length + 7;

    int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);

    for(int i = 0; i < frequencies_size; i++)
    {
        if(sampling_frequencies[i] == samplerate)
        {
            sampling_frequency_index = i;
            break;
        }
    }

    p_adts_header[0] = 0xff;
    p_adts_header[1] = 0xf0;
    p_adts_header[1] |= (0 << 3);
    p_adts_header[1] |= (0 << 1);
    p_adts_header[1] |= 1;

    p_adts_header[2] = (profile)<<6;
    p_adts_header[2] |= (sampling_frequency_index & 0x0f)<<2;
    p_adts_header[2] |= (0 << 1);
    p_adts_header[2] |= (channels & 0x04)>>2;

    p_adts_header[3] = (channels & 0x03)<<6;
    p_adts_header[3] |= (0 << 5);
    p_adts_header[3] |= (0 << 4);
    p_adts_header[3] |= (0 << 3);
    p_adts_header[3] |= (0 << 2);
    p_adts_header[3] |= ((adtsLen & 0x1800) >> 11);

    p_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);
    p_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);
    p_adts_header[5] |= 0x1f;
    p_adts_header[6] = 0xfc;
    return 0;
}



int main(int argc, char **argv)
{

    char *in_filename = "/home/yx/media_file/believe.mp4";
    char *h264_filename = "/home/yx/media_file/believe.h264";
    char *aac_filename = "/home/yx/media_file/believe.aac";

    FILE *aac_fd = NULL;
    FILE *h264_fd = NULL;

    h264_fd = fopen(h264_filename, "wb");
    aac_fd = fopen(aac_filename, "wb");

    AVFormatContext *ifmt_ctx = NULL;
    int video_index = -1;
    int audio_index = -1;
    AVPacket *pkt = NULL;

    ifmt_ctx = avformat_alloc_context();


    avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL);                                // 将媒体流与解复用器相关联

    video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);       // 查找视频流标签
    audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);       // 查找音频流标签

    const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb");             // 查找H264过滤器

    AVBSFContext *bsf_ctx = NULL;
    av_bsf_alloc(bsfilter, &bsf_ctx);
    avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[video_index]->codecpar);
    av_bsf_init(bsf_ctx);                                                                   // 初始化过滤器

    pkt = av_packet_alloc();
    av_init_packet(pkt);
    while (1)
    {
        if(av_read_frame(ifmt_ctx, pkt) < 0)                                                // 逐个包读取
            break;
        if(pkt->stream_index == video_index)
        {
            av_bsf_send_packet(bsf_ctx, pkt);                                               // 视频包就将包发给过滤器

            while (1)
            {
                if(av_bsf_receive_packet(bsf_ctx, pkt) != 0)                                // 从过滤器接收包
                    break;
                size_t size = fwrite(pkt->data, 1, pkt->size, h264_fd);                     // 将包写到输出文件
                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);                // 音频包构建ADTS帧头部
            fwrite(adts_header_buf, 1, 7, aac_fd);                                          // 将头部写到输出文件
            size_t size = fwrite( pkt->data, 1, pkt->size, aac_fd);                         // 将AAC包写到输出文件

            av_packet_unref(pkt);                                                           // 引用计数--
        }
        else
        {
            av_packet_unref(pkt);
        }
    }

    printf("while finish\n");
    printf("Hello World!\n");
    return 0;
}
相关推荐
盲盒Q1 天前
《解码者:暗流》
视频编解码
骄傲的心别枯萎2 天前
RV1126 NO.48:RV1126+OPENCV在视频中添加时间戳
人工智能·opencv·计算机视觉·音视频·视频编解码·rv1126
他们叫我一代大侠3 天前
ARMV9.7 FEAT_SME2p3 视频编解码器新增指令扩展
视频编解码
骄傲的心别枯萎3 天前
RV1126 NO.37:OPENCV的图像叠加功能
人工智能·opencv·计算机视觉·音视频·视频编解码·rv1126
Industio_触觉智能9 天前
【开源鸿蒙-AVCodec Kit】音视频编解码封装解封装部件介绍,转自开源鸿蒙官媒OpenAtom OpenHarmony
harmonyos·视频编解码·openharmony·开源鸿蒙
DogDaoDao10 天前
OpenCV音视频编解码器详解
人工智能·opencv·音视频·视频编解码·h264·h265·音视频编解码
嵌入式-老费14 天前
Easyx图形库应用(视频编解码和网络传输)
视频编解码
weixin_Todd_Wong201015 天前
基于海思AI ISP视频编解码IPC平台的算法承载方案
接口隔离原则·视频编解码
EasyCVR16 天前
浅述视频汇聚平台EasyCVR视频编解码与转码技术如何成就视频体验
音视频·视频编解码
♛小小小让让20 天前
H264 H265 编码器 解码器原理
opencv·视频编解码