ffmpeg解码后变快了

时间:2021-10-30 14:38:53
    我想把mp4里的音频用ffmpeg的api转为mp2文件保存,碰到很多问题。

    转过去之后时间总是不对,于是我把avcodec_decode_audio4解码之后的源始文件直接保存为pcm格式的文件并用播放器进行播放,结果播放的速度快了一倍,播放器设置的采样率为44100,当我把它设为22050的时候时间相符了,而且播放也正常了。

    我又看了下原始的mp4里的音频就是22050的采样率,我想如果能把22050的采样率转为44100的码率再转为mp2文件就应当正常了。ffmpeg里有提供方法进行转换吗?我试了用swr_convert方进行转换,好像还是不行。

    还有个问题,我用avcodec_decode_audio4解出来的原始音频文件能直接用mp3lame转为mp3的格式吗?

8 个解决方案

#1


第一个问题,说明源是22.05KHz的音频,所以按照44.1KHz来播放,肯定是会有问题的。ffmpeg中的swr_convert就是用来做格式转换的,包括重采样。应该是可以的,你可以把你的代码贴出来看看。
第二个问题,avcodec_decode_audio4解出来的音频是否可以用mp3lame转mp3,要看mp3lame是否支持pcm这种没有描述的文件格式了,作为一个开源软件,我认为应该是支持的。

#2


下面是我转码的代码,很乱,帮忙看看。我试了几个mp4的文件都有问题,如果源mp4是44100那它就变长变慢了,另一个mp4是22050,结果重采样之后本来是3分33秒的变成了1分59秒,但这1分59秒播放却很正常。1分59秒以后的就没了。我用一个播放器把转换出来的mp2文件用22050的采样率载入之后地却发现整首歌的音频都在。但播放声音变化很大,杂音也很大。是不是我重采样的参数有错误?

JNIEXPORT void JNICALL Java_com_example_ffmpegtest_Ffmpegs_isrun (JNIEnv * env , jobject obj) {

unsigned char *pEnCodeBuf = (char *)malloc(MAX_BUF_SIZE);
char *sourceFile = "/mnt/sdcard/test.mp4";
av_register_all();


/**
 * 视频流解码部分
 */
//01 打开输入文件
if(avformat_open_input(&fmt_ctx , sourceFile , NULL , NULL)) {
LOGI("打开文件失败01");
return;
}

//02  取得流信息
if(avformat_find_stream_info(fmt_ctx , NULL) < 0) {
LOGI("取得流信息失败02");
return;
}

int s = fmt_ctx->nb_streams;

LOGI("nb_streams is %d" , s);
//return;

//03 判断流是否能正常打开
AVCodec *pInputCodec = NULL;
video_stream_idx = av_find_best_stream(fmt_ctx , AVMEDIA_TYPE_VIDEO , -1, -1, &pInputCodec, 0);
if(-1 == video_stream_idx)
{
//没有找到视频流
LOGI("没有找到视频流03");
return;
}

video_stream = fmt_ctx -> streams[video_stream_idx];

video_dec_ctx = video_stream->codec;


pInputCodec = avcodec_find_decoder(video_dec_ctx->codec_id);
if(NULL == pInputCodec)
{
//没有找到解码器
LOGI("没有找到解码器");
return;
}
LOGI("视频流是%d" , video_stream_idx);

if(avcodec_open2(video_dec_ctx , pInputCodec,NULL) != 0)
{
//打开解码器失败
LOGI("打开解码器失败");
return;
}

/**
 * 音频流解码部分
 */
//03 判断流是否能正常打开
AVCodec *aupInputCodec = NULL;
int au_stream_idx = -1;
au_stream_idx = av_find_best_stream(fmt_ctx , AVMEDIA_TYPE_AUDIO, -1, -1, &aupInputCodec, 0);
if(-1 == au_stream_idx)
{
//没有找到视频流
LOGI("没有找到视频流03");
return;
}

audio_stream = fmt_ctx -> streams[au_stream_idx];
audio_dec_ctx = audio_stream->codec;
aupInputCodec = avcodec_find_decoder(audio_dec_ctx->codec_id);
if(NULL == pInputCodec)
{
//没有找到解码器
LOGI("没有找到解码器");
return;
}

if(avcodec_open2(audio_dec_ctx , aupInputCodec , NULL) != 0)
{
//打开解码器失败
LOGI("打开解码器失败");
return;
}
av_dump_format( fmt_ctx , -1 , sourceFile , 0);

/**
 * 编码初始化
 */

AVFormatContext * outOc = NULL;
const char* filename = "/mnt/sdcard/testt.mp2";
AVOutputFormat *outFmt = NULL;
AVCodecContext *c = NULL;
AVCodec * outCodec;

if(avformat_alloc_output_context2(&outOc , NULL , NULL , filename) < 0){
LOGI("申请空间失败");
return;
}

outFmt = av_guess_format(NULL , filename , NULL);
if(NULL == outFmt){
LOGI("没有找到合适的容器");
return;
}

outCodec = avcodec_find_encoder(AV_CODEC_ID_MP2);
if(outCodec == NULL){
LOGI("没有找到mp2的编码器");
return;
}

c = avcodec_alloc_context3(outCodec);
c->sample_fmt  = AV_SAMPLE_FMT_S16;
c->bit_rate    = 64000;
c->sample_rate = 44100;
c->channels    = 2;
c->channel_layout = AV_CH_LAYOUT_STEREO;
//c->bits_per_coded_sample = 2;

int avo = 5;
avo = avcodec_open2(c, outCodec, NULL);
if(avo < 0){
LOGI("打开编码器出错%d" , avo);
return;
}

AVStream * outSt = avformat_new_stream(outOc , outCodec);
if(NULL == outSt){
LOGI("没有找到合适的流");
return;
}

av_dump_format(outOc, 0, filename, 1);

outSt->id = 1;



/**
 * 文件读取部分
 */



av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
int isOk = -1;




int v = 0 , a = 0;
outFrame = avcodec_alloc_frame();
if(outFrame == NULL){
LOGI("frame分配内存失败");
return;
}
outFrame->nb_samples = c->frame_size;
outFrame->format = c->sample_fmt;
outFrame->channels = c->channels;
outFrame->channel_layout = c->channel_layout;
outFrame->linesize[0] = 2 * 4 * 44100 ;
outFrame->extended_data = outFrame->data[0] = av_malloc(outFrame->linesize[0]);

int outPktPts = 1;

AVPacket  outPkt = {0};
int m_nAudioTimeStamp = 0;

int ao = 5;
ao = avio_open(&outOc->pb , filename , AVIO_FLAG_WRITE);
if(ao < 0){
LOGI("打开文件出错%d" , ao);
return;
}

int aw = 5;
avformat_write_header(outOc , NULL);
if(aw < 0){
LOGI("写文件头失败%d" , aw);
return;
}

double audio_pts;

 AVFrame *frame = avcodec_alloc_frame();

 uint8_t *pktdata;
 int pktsize;



 //重采样





 struct SwrContext *swr_ctx ;
 swr_ctx = swr_alloc();

 if(!swr_ctx){
 LOGI("sssssss");
 return;
 }


av_opt_set_int(swr_ctx, "in_channel_layout",audio_dec_ctx->channel_layout, 0);
av_opt_set_int(swr_ctx, "in_sample_rate",   22050, 0);
av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_FLTP , 0);

av_opt_set_int(swr_ctx, "out_channel_layout",c->channel_layout, 0);
av_opt_set_int(swr_ctx, "out_sample_rate",   c->sample_rate, 0);
av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);



int wret = swr_init(swr_ctx);
if(wret < 0){
LOGI("I'm no");
return;
}


int mysize = 0;
int my = 0;
int ok = 0;
int64_t mypts = 0;


while(1) {



int got_frame = 0 , ret = 0 , got_packet_ptr = 5 , aa = 5;
isOk = av_read_frame(fmt_ctx, &pkt);
if(isOk >= 0) {


my++;
//视频处理
if(video_stream_idx == pkt.stream_index) {
v++;

}

//音频处理
if(au_stream_idx == pkt.stream_index) {

                pktdata = pkt.data;
                pktsize = pkt.size;


                while(pktsize > 0){

     ret = avcodec_decode_audio4(audio_dec_ctx, frame, &got_frame, &pkt);

     if(ret < 0){

     break;
     }


                    pktsize -= ret;
                    pktdata += ret;
                    pkt.dts = pkt.pts = AV_NOPTS_VALUE;
     if (got_frame) {


     int wr = swr_convert(swr_ctx , outFrame->data , outFrame->nb_samples , (const uint8_t **)frame->data, frame->nb_samples);


     outFrame->linesize[0] = frame->linesize[0];


     av_init_packet(&outPkt);
     outPkt.data = NULL;
     outPkt.size = 0;

     aa = avcodec_encode_audio2(c , &outPkt, outFrame , &got_packet_ptr);

     outPkt.pts = av_rescale_q(outPkt.pts, c->time_base, outSt->time_base);

     char ch[256];
      av_strerror(aa , ch , 256);

     if(aa < 0){
     //LOGI("编成帧失败入");

     }else{
     //LOGI("编成帧成功");
     outPkt.stream_index = outSt->index;
     //outPkt.pts = pkt.pts;



     av_interleaved_write_frame(outOc , &outPkt);
     v++;
     ok = 0;




     }

     a++;



     }
                }

}

} else {

LOGI("读完了");
break;

}

av_free_packet(&pkt);
}

av_write_trailer(outOc);

LOGI("成功 v = %d , a = %d , mysize = %d , my = %d" , v , a , mysize , my);
return;

}

#3


outFrame->linesize[0] = frame->linesize[0];
这行代码有问题。你为什么这么写?

#4


linesize[0]我查资料说是outFrame->data[0]的大小,但我试了,这行不写也是一样,我直接让它等0还是一样。我看我还是看看ffmepg.c是怎么写的算了。

#5


仅仅只是mark

#6


需要进行重采样,然后进行格式转换。。。。

#7


该回复于2015-03-20 15:23:47被管理员删除

#8


http://blog.csdn.net/zhuweigangzwg/article/details/43733673 用ffmpeg实现音频resample(重采样)

#1


第一个问题,说明源是22.05KHz的音频,所以按照44.1KHz来播放,肯定是会有问题的。ffmpeg中的swr_convert就是用来做格式转换的,包括重采样。应该是可以的,你可以把你的代码贴出来看看。
第二个问题,avcodec_decode_audio4解出来的音频是否可以用mp3lame转mp3,要看mp3lame是否支持pcm这种没有描述的文件格式了,作为一个开源软件,我认为应该是支持的。

#2


下面是我转码的代码,很乱,帮忙看看。我试了几个mp4的文件都有问题,如果源mp4是44100那它就变长变慢了,另一个mp4是22050,结果重采样之后本来是3分33秒的变成了1分59秒,但这1分59秒播放却很正常。1分59秒以后的就没了。我用一个播放器把转换出来的mp2文件用22050的采样率载入之后地却发现整首歌的音频都在。但播放声音变化很大,杂音也很大。是不是我重采样的参数有错误?

JNIEXPORT void JNICALL Java_com_example_ffmpegtest_Ffmpegs_isrun (JNIEnv * env , jobject obj) {

unsigned char *pEnCodeBuf = (char *)malloc(MAX_BUF_SIZE);
char *sourceFile = "/mnt/sdcard/test.mp4";
av_register_all();


/**
 * 视频流解码部分
 */
//01 打开输入文件
if(avformat_open_input(&fmt_ctx , sourceFile , NULL , NULL)) {
LOGI("打开文件失败01");
return;
}

//02  取得流信息
if(avformat_find_stream_info(fmt_ctx , NULL) < 0) {
LOGI("取得流信息失败02");
return;
}

int s = fmt_ctx->nb_streams;

LOGI("nb_streams is %d" , s);
//return;

//03 判断流是否能正常打开
AVCodec *pInputCodec = NULL;
video_stream_idx = av_find_best_stream(fmt_ctx , AVMEDIA_TYPE_VIDEO , -1, -1, &pInputCodec, 0);
if(-1 == video_stream_idx)
{
//没有找到视频流
LOGI("没有找到视频流03");
return;
}

video_stream = fmt_ctx -> streams[video_stream_idx];

video_dec_ctx = video_stream->codec;


pInputCodec = avcodec_find_decoder(video_dec_ctx->codec_id);
if(NULL == pInputCodec)
{
//没有找到解码器
LOGI("没有找到解码器");
return;
}
LOGI("视频流是%d" , video_stream_idx);

if(avcodec_open2(video_dec_ctx , pInputCodec,NULL) != 0)
{
//打开解码器失败
LOGI("打开解码器失败");
return;
}

/**
 * 音频流解码部分
 */
//03 判断流是否能正常打开
AVCodec *aupInputCodec = NULL;
int au_stream_idx = -1;
au_stream_idx = av_find_best_stream(fmt_ctx , AVMEDIA_TYPE_AUDIO, -1, -1, &aupInputCodec, 0);
if(-1 == au_stream_idx)
{
//没有找到视频流
LOGI("没有找到视频流03");
return;
}

audio_stream = fmt_ctx -> streams[au_stream_idx];
audio_dec_ctx = audio_stream->codec;
aupInputCodec = avcodec_find_decoder(audio_dec_ctx->codec_id);
if(NULL == pInputCodec)
{
//没有找到解码器
LOGI("没有找到解码器");
return;
}

if(avcodec_open2(audio_dec_ctx , aupInputCodec , NULL) != 0)
{
//打开解码器失败
LOGI("打开解码器失败");
return;
}
av_dump_format( fmt_ctx , -1 , sourceFile , 0);

/**
 * 编码初始化
 */

AVFormatContext * outOc = NULL;
const char* filename = "/mnt/sdcard/testt.mp2";
AVOutputFormat *outFmt = NULL;
AVCodecContext *c = NULL;
AVCodec * outCodec;

if(avformat_alloc_output_context2(&outOc , NULL , NULL , filename) < 0){
LOGI("申请空间失败");
return;
}

outFmt = av_guess_format(NULL , filename , NULL);
if(NULL == outFmt){
LOGI("没有找到合适的容器");
return;
}

outCodec = avcodec_find_encoder(AV_CODEC_ID_MP2);
if(outCodec == NULL){
LOGI("没有找到mp2的编码器");
return;
}

c = avcodec_alloc_context3(outCodec);
c->sample_fmt  = AV_SAMPLE_FMT_S16;
c->bit_rate    = 64000;
c->sample_rate = 44100;
c->channels    = 2;
c->channel_layout = AV_CH_LAYOUT_STEREO;
//c->bits_per_coded_sample = 2;

int avo = 5;
avo = avcodec_open2(c, outCodec, NULL);
if(avo < 0){
LOGI("打开编码器出错%d" , avo);
return;
}

AVStream * outSt = avformat_new_stream(outOc , outCodec);
if(NULL == outSt){
LOGI("没有找到合适的流");
return;
}

av_dump_format(outOc, 0, filename, 1);

outSt->id = 1;



/**
 * 文件读取部分
 */



av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
int isOk = -1;




int v = 0 , a = 0;
outFrame = avcodec_alloc_frame();
if(outFrame == NULL){
LOGI("frame分配内存失败");
return;
}
outFrame->nb_samples = c->frame_size;
outFrame->format = c->sample_fmt;
outFrame->channels = c->channels;
outFrame->channel_layout = c->channel_layout;
outFrame->linesize[0] = 2 * 4 * 44100 ;
outFrame->extended_data = outFrame->data[0] = av_malloc(outFrame->linesize[0]);

int outPktPts = 1;

AVPacket  outPkt = {0};
int m_nAudioTimeStamp = 0;

int ao = 5;
ao = avio_open(&outOc->pb , filename , AVIO_FLAG_WRITE);
if(ao < 0){
LOGI("打开文件出错%d" , ao);
return;
}

int aw = 5;
avformat_write_header(outOc , NULL);
if(aw < 0){
LOGI("写文件头失败%d" , aw);
return;
}

double audio_pts;

 AVFrame *frame = avcodec_alloc_frame();

 uint8_t *pktdata;
 int pktsize;



 //重采样





 struct SwrContext *swr_ctx ;
 swr_ctx = swr_alloc();

 if(!swr_ctx){
 LOGI("sssssss");
 return;
 }


av_opt_set_int(swr_ctx, "in_channel_layout",audio_dec_ctx->channel_layout, 0);
av_opt_set_int(swr_ctx, "in_sample_rate",   22050, 0);
av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_FLTP , 0);

av_opt_set_int(swr_ctx, "out_channel_layout",c->channel_layout, 0);
av_opt_set_int(swr_ctx, "out_sample_rate",   c->sample_rate, 0);
av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);



int wret = swr_init(swr_ctx);
if(wret < 0){
LOGI("I'm no");
return;
}


int mysize = 0;
int my = 0;
int ok = 0;
int64_t mypts = 0;


while(1) {



int got_frame = 0 , ret = 0 , got_packet_ptr = 5 , aa = 5;
isOk = av_read_frame(fmt_ctx, &pkt);
if(isOk >= 0) {


my++;
//视频处理
if(video_stream_idx == pkt.stream_index) {
v++;

}

//音频处理
if(au_stream_idx == pkt.stream_index) {

                pktdata = pkt.data;
                pktsize = pkt.size;


                while(pktsize > 0){

     ret = avcodec_decode_audio4(audio_dec_ctx, frame, &got_frame, &pkt);

     if(ret < 0){

     break;
     }


                    pktsize -= ret;
                    pktdata += ret;
                    pkt.dts = pkt.pts = AV_NOPTS_VALUE;
     if (got_frame) {


     int wr = swr_convert(swr_ctx , outFrame->data , outFrame->nb_samples , (const uint8_t **)frame->data, frame->nb_samples);


     outFrame->linesize[0] = frame->linesize[0];


     av_init_packet(&outPkt);
     outPkt.data = NULL;
     outPkt.size = 0;

     aa = avcodec_encode_audio2(c , &outPkt, outFrame , &got_packet_ptr);

     outPkt.pts = av_rescale_q(outPkt.pts, c->time_base, outSt->time_base);

     char ch[256];
      av_strerror(aa , ch , 256);

     if(aa < 0){
     //LOGI("编成帧失败入");

     }else{
     //LOGI("编成帧成功");
     outPkt.stream_index = outSt->index;
     //outPkt.pts = pkt.pts;



     av_interleaved_write_frame(outOc , &outPkt);
     v++;
     ok = 0;




     }

     a++;



     }
                }

}

} else {

LOGI("读完了");
break;

}

av_free_packet(&pkt);
}

av_write_trailer(outOc);

LOGI("成功 v = %d , a = %d , mysize = %d , my = %d" , v , a , mysize , my);
return;

}

#3


outFrame->linesize[0] = frame->linesize[0];
这行代码有问题。你为什么这么写?

#4


linesize[0]我查资料说是outFrame->data[0]的大小,但我试了,这行不写也是一样,我直接让它等0还是一样。我看我还是看看ffmepg.c是怎么写的算了。

#5


仅仅只是mark

#6


需要进行重采样,然后进行格式转换。。。。

#7


该回复于2015-03-20 15:23:47被管理员删除

#8


http://blog.csdn.net/zhuweigangzwg/article/details/43733673 用ffmpeg实现音频resample(重采样)