ffmpeg C代码实现 PCM音频编码

应用到的API及解释

avcodec_register_all:注册FFmpeg所有编解码器。
 
avformat_alloc_output_context2():初始化输出码流的AVFormatContext。
 
avio_open():打开输出文件。
 
av_new_stream():创建输出码流的AVStream。
 
avcodec_find_encoder():查找编码器。
 
avcodec_open2():打开编码器。
 
avformat_write_header():写文件头(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。
 
avcodec_encode_audio2():编码音频。即将AVFrame(存储PCM采样数据)编码为AVPacket(存储AAC,MP3等格式的码流数据)。
 
av_write_frame():将编码后的视频码流写入文件。
 
av_write_trailer():写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。

源代码如下:

#include 
#include 
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/log.h"
#include "libswresample/swresample.h"
AVFormatContext* inputContext;
AVFormatContext* outputContext;
AVCodecContext* decodeContext;
AVCodecContext* encodeContext;
AVStream* stream;
void init(){
    avcodec_register_all();
}
int open_output_context(char* filename){
    outputContext = avformat_alloc_context();
    int ret = avformat_alloc_output_context2(&outputContext,NULL,NULL,filename);
    if(ret < 0){
        av_log(NULL,AV_LOG_ERROR,"create outputContext failed \n");
        return -1;
    }else{
        av_log(NULL,AV_LOG_INFO,"create outputContext success \n");
    }
    ret = avio_open(&outputContext->pb,filename,AVIO_FLAG_READ_WRITE);
    if(ret < 0){
        av_log(NULL,AV_LOG_ERROR,"open file failed  \n");
        return -1;
    }else{
          av_log(NULL,AV_LOG_INFO,"open file success  \n");
    }
    stream = avformat_new_stream(outputContext,NULL);
    if(!stream){
        av_log(NULL,AV_LOG_ERROR,"avformat_new_stream failed  \n");
        return -1;
    }else{
        av_log(NULL,AV_LOG_INFO,"avformat_new_stream success  \n");
    }
    av_dump_format(outputContext,0,filename,1);
    return ret;
}
void close(){
    if(decodeContext){
        avcodec_close(decodeContext);
    }
    if(inputContext){
        avformat_close_input(&inputContext);
    }
    if(outputContext){
        for(int i = 0 ; i < outputContext->nb_streams; i++){
            AVCodecContext* codecContext = outputContext->streams[i]->codec;
            avcodec_close(codecContext);
        }
        avformat_close_input(&outputContext);
    }
}
int init_encode(AVStream* audio_stream){ 
    encodeContext = audio_stream->codec;
    encodeContext->codec = outputContext->audio_codec;
	encodeContext->codec_id = outputContext->audio_codec_id;
	encodeContext->codec_type = AVMEDIA_TYPE_AUDIO;
    /* check that the encoder supports s16 pcm input */
    encodeContext->sample_fmt = AV_SAMPLE_FMT_S16;
    encodeContext->sample_rate    = 44100;
    encodeContext->channel_layout=AV_CH_LAYOUT_STEREO;
    encodeContext->channels       = av_get_channel_layout_nb_channels(encodeContext->channel_layout);
    encodeContext->bit_rate = 64000; 
    AVCodec* pCodec = avcodec_find_encoder_by_name("libfdk_aac");
     if(pCodec){
        av_log(NULL,AV_LOG_INFO,"avcodec_find_encoder success\n");
     }else{
        av_log(NULL,AV_LOG_ERROR,"avcodec_find_encoder failed\n");
        return -1;
     }
    return avcodec_open2(encodeContext,pCodec,NULL);
}
static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt)
{
    int ret;
    /* send the frame to the encoder */
    if (frame)
        printf("Send frame %3"PRId64"\n", frame->pts);
    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }
    while (ret >= 0) {
        ret = avcodec_receive_packet(enc_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during encoding\n");
            exit(1);
        }
        printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
        av_write_frame(outputContext,pkt);
        av_packet_unref(pkt);
    }
}
int main(){
    init();
    char* inputFile = "jichi.pcm";
    char* outputFile = "jichi2.aac";
    FILE* in_file = fopen(inputFile,"rb");
    if(in_file){
        av_log(NULL,AV_LOG_INFO,"open file success \n");
    }else{
        av_log(NULL,AV_LOG_ERROR,"can't open file! \n");
        goto _END;
    }

    int ret = open_output_context(outputFile);
    if(ret >= 0){
        av_log(NULL,AV_LOG_INFO,"open_output_context success \n");
    }else{
        av_log(NULL,AV_LOG_ERROR,"open_output_context failed! \n");
         goto _END;
    }
   
	if (stream==NULL){
        av_log(NULL,AV_LOG_ERROR,"avformat_new_stream failed \n");
		goto _END;
	}else{
        av_log(NULL,AV_LOG_INFO,"avformat_new_stream success \n");
    }

    ret = init_encode(stream);
    if(ret < 0){
        av_log(NULL,AV_LOG_ERROR,"init_encoder failed \n");
        goto _END;
    }else{
        av_log(NULL,AV_LOG_INFO,"init encoder success \n");
    }
    ret = avcodec_parameters_from_context(stream->codecpar, encodeContext);
    if(ret < 0){
        printf("avcodec_parameters_from_context failed \n");
    }else{
        printf("avcodec_parameters_from_context success \n");
    }

    AVFrame* pFrame = av_frame_alloc();
    pFrame->nb_samples= encodeContext->frame_size;
    pFrame->format= encodeContext->sample_fmt;
 
    int size = av_samples_get_buffer_size(NULL, encodeContext->channels,encodeContext->frame_size,encodeContext->sample_fmt, 1);
    int8_t* frame_buf = (uint8_t *)av_malloc(size);
    avcodec_fill_audio_frame(pFrame, encodeContext->channels, encodeContext->sample_fmt,(const uint8_t*)frame_buf, size, 1);
 
    //Write Header
    avformat_write_header(outputContext,NULL);
    AVPacket pkt;
    av_new_packet(&pkt,size);
    int got_frame;
    int i = 0;
    while(1){   
       if (fread(frame_buf, 1, size, in_file) <= 0){
            printf("Failed to read raw data! \n");
            break;
        }else if(feof(in_file)){
            break;
        }
        pFrame->data[0] = frame_buf;  //PCM Data
        pFrame->pts=i*100;
        encode(encodeContext,pFrame,&pkt);
        i++;
    }
    av_write_trailer(outputContext);
    printf("编码完成\n");
    AVCodec* encoder = avcodec_find_encoder(outputContext->oformat->audio_codec);
    if(!encoder){
        av_log(NULL,AV_LOG_ERROR,"can't find endcoder \n");
    }else{
        av_log(NULL,AV_LOG_INFO," find endcoder \n");
        av_log(NULL,AV_LOG_ERROR,"encoder name = %s \n",encoder->name);
    }
    av_free(frame_buf);
     _END:
        av_frame_unref(pFrame);
        if(in_file){
            fclose(in_file);
        }
        close();
    return 0;
}

你可能感兴趣的:(ffmpeg)