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;
}
相关推荐
q5507071771 天前
格式转换专家视频格式转换教程
视频编解码·视频处理·格式工厂
TSINGSEE4 天前
国标GB28181视频质量诊断:EasyGBS服务插件EasyVQD快速识别花屏、蓝屏、画面冻结抖动
人工智能·音视频·实时音视频·视频编解码·视频质量诊断·花屏检测·画面抖动
ℳ₯㎕ddzོꦿ࿐10 天前
告别延迟:HLS (m3u8) 实时转 FLV 全栈方案实战
视频编解码
霜雪i11 天前
ISP模式
视频编解码·h.266
CheungChunChiu11 天前
视频编解码与 GOP 结构详解
linux·视频编解码
深圳市友昊天创科技有限公司15 天前
友昊天创推出8K ,4K 120Hz 100米延长器方案
音视频·实时音视频·视频编解码
深圳市友昊天创科技有限公司15 天前
ASM4242 雷电扩展坞 CV4242 PCIE扩展坞
音视频·实时音视频·视频编解码
深圳市友昊天创科技有限公司15 天前
友昊天创推出延长器方案GSV5600+HDBase VS010**/VS100**
音视频·实时音视频·视频编解码
TEL1892462247719 天前
IT6227:USB-C(DP Alt 模式)及电源传输控制器 内置 4 通道 DP 1.4 转 HDMI 2.1 转换器
音视频·实时音视频·视频编解码
小咖自动剪辑22 天前
视频去水印与去字幕教程:免费去水印软件与去字幕工具推荐
人工智能·音视频·实时音视频·视频编解码