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;
}
相关推荐
TSINGSEE2 天前
人员抽烟AI检测算法在智慧安防领域的创新应用,助力监控智能化
人工智能·算法·视频编解码·安防视频监控·视频监控管理平台
__Destiny__2 天前
视频格式转为mp4(使用ffmpeg)
ffmpeg·视频编解码
PlumCarefree3 天前
USB摄像头视频流转RTSP流
图像处理·ffmpeg·音视频·媒体·视频编解码
TSINGSEE3 天前
解码未来:H.265与H.266技术对比及EasyCVR视频汇聚平台编码技术优势
音视频·h.265·视频编解码·安防视频监控·视频监控管理平台·h.266
EasyCVR6 天前
视频监控平台是如何运作的?EasyCVR视频汇聚平台的高效策略与实践
人工智能·音视频·视频编解码·视频监控·监控视频接入
Q8343158196 天前
海思SD3403(21AP10, 108DC2910 )4K60 的 ISP 图像处理能力,4Tops INT8算力
linux·图像处理·人工智能·嵌入式硬件·视觉检测·视频编解码
哈~~哈~7 天前
RV1126采集VI视频数据流
linux·音视频·视频编解码
fxybg20228 天前
2024年录屏神器大盘点,轻松捕捉屏幕精彩
电脑·音视频·实时音视频·视频编解码·视频
DogDaoDao9 天前
AV1 Bitstream & Decoding Process Specification:约定
音视频·视频编解码·av1·vp9·libaom·aom
TSINGSEE10 天前
打造安心宠物乐园:EasyCVR平台赋能猫咖/宠物店的智能视频监控解决方案
音视频·视频编解码·安防视频监控·宠物·视频监控管理平台