FFMPEG 4.0 for Android preparations
FFMPEG4.0 audio decoding decapsulation
The following function method based on the latest FFMPEG 4.0 (4.X):
This article focuses on how to get raw data from a pcm file, a file generated audio format we need to use the original data, combined with the previous FFMPEG4.0 audio decoding solution package , you will be able to achieve audio format conversion.
PCM data read from a file generated MP3 format.
First, the initialization output
AVFormatContext *fmt_ctx;
int ret = avformat_alloc_output_context2(&fmt_ctx,NULL,NULL,out_file);
ret = avio_open(&fmt_ctx->pb,out_file,AVIO_FLAG_WRITE);
The following variables are not necessary, which kept the output format information, comprising generating audio and video encoding format.
AVOutputFormat *ofmt;
ofmt = fmt_ctx->oformat;
Second, prepare the encoder, stream encoding parameter set
encodec = avcodec_find_encoder(AV_CODEC_ID_MP3);//可通过ofmt->audio_codec得到格式
st = avformat_new_stream(fmt_ctx,encodec);
encodec_ctx = avcodec_alloc_context3(encodec);
encodec_ctx->sample_rate = 44100;
encodec_ctx->bit_rate = 64000;
encodec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
encodec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
encodec_ctx->channels = av_get_channel_layout_nb_channels(encodec_ctx->channel_layout);
Third, the open encoder, the number of samples to obtain a data
ret = avcodec_open2(encodec_ctx,encodec,NULL);
int encode_nb_sample = encodec_ctx->frame_size;
Fourth, the initialization frame and packet
frame = av_frame_alloc();
pkt = av_packet_alloc();
frame->nb_samples = encode_nb_sample;
frame->format = encodec_ctx->sample_fmt;
frame->channel_layout = encodec_ctx->channel_layout;
//frame.data 需要申请的字节数
int size = av_samples_get_buffer_size(NULL,encodec_ctx->channels,encode_nb_sample,encodec_ctx->sample_fmt,1);
uint8_t *frame_buf = (uint8_t *) av_malloc(size);
avcodec_fill_audio_frame(frame,encodec_ctx->channels,encodec_ctx->sample_fmt,frame_buf,size,1);
The above method of the frame data to the memory allocation can be achieved (sample the method) by calling the following methods:ret = av_frame_get_buffer(frame, 0);
Resampling pcm data is read from a file, where a number of samples obtained conversion data to be read is calculated according to the number of samples generated frame data (the sampling rate is 44,100 samples pcm) (examples herein are on a network ! their example is wrong no problem when the sample rate does not change, there is a change in playing time):int in_nb_sample = av_rescale_rnd(frame->nb_samples,44100,encodec_ctx->sample_rate,AV_ROUND_UP);
Calculating a desired data conversion buf Size:
int readSize = in_nb_sample * av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO) * av_get_bytes_per_sample(in_fmt);
char *read_buf = (char*)malloc(readSize);
Fifth, replication parameters, write header information
avcodec_parameters_from_context(st->codecpar,encodec_ctx);
avformat_write_header(fmt_ctx,NULL);
Sixth, the parameter setting resampling
swc = swr_alloc();
av_opt_set_int(swc,"in_channel_layout",AV_CH_LAYOUT_STEREO,0);
av_opt_set_int(swc,"in_sample_rate",in_sample_rate,0);
av_opt_set_sample_fmt(swc,"in_sample_fmt",in_fmt,0);
av_opt_set_int(swc,"out_channel_layout",encodec_ctx->channel_layout,0);
av_opt_set_int(swc,"out_sample_rate",encodec_ctx->sample_rate,0);
av_opt_set_sample_fmt(swc,"out_sample_fmt",encodec_ctx->sample_fmt,0);
ret = swr_init(swc);
Seven coding (coded following is an actual encoding process should be repeated cycles of the following acts, until the file read)
1. pcm read file pointer array prepared resampling approach is to use some ffmpeg Frame interface generation, of the frame were data memory allocation, the essence is the same:
if (fread(read_buf, 1, readSize, infile) < 0) {
printf("文件读取错误!\n");
return -1;
} else if (feof(infile)) {
break;
}
//重采样源数据
const uint8_t *indata[AV_NUM_DATA_POINTERS] = {0};
indata[0] = (uint8_t *) read_buf;
2. Resampling provided pts
int len = swr_convert(swc, frame->data, frame->nb_samples,indata, in_nb_sample);
LOGV("len = %d\n",len);
frame->pts = apts;
apts += av_rescale_q(len,(AVRational){1,encodec_ctx->sample_rate},encodec_ctx->time_base);
3. coding (maybe not while loop. After reading the note file needs to send it once, frame pass NULL, mainly in order to flush the encoder)
ret = avcodec_send_frame(encodec_ctx, frame);
while(ret >= 0) {
LOGV("receiver\n");
ret = avcodec_receive_packet(encodec_ctx, pkt);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "%s,ret = %d\n", "avcodec_receive_packet!error ",ret);
break;
}
pkt->stream_index = st->index;
av_log(NULL, AV_LOG_DEBUG, "第%d帧\n", i);
pkt->pts = av_rescale_q(pkt->pts, encodec_ctx->time_base, st->time_base);
pkt->dts = av_rescale_q(pkt->dts, encodec_ctx->time_base, st->time_base);
pkt->duration = av_rescale_q(pkt->duration, encodec_ctx->time_base, st->time_base);
LOGV("duration = %d,dts=%d,pts=%d\n",pkt->duration,pkt->dts,pkt->pts);
ret = av_write_frame(fmt_ctx, pkt);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "av_write_frame error!");
}
av_packet_unref(pkt);
}
4. Write terminatorav_write_trailer(fmt_ctx);