FFmpeg--解码:mp4文件解码为音频aac和视频h264

mp4文件解封装:

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

流程

FFmpeg--解码:mp4文件解码为音频aac和视频h264_第1张图片

code

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

#include 

#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返回值的错误string

    ifmt_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_mp4toannexb
    const 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 data
            if(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,aac)