使用 ffmpeg 和 libvorbis 编码 webm 不起作用
Posted
技术标签:
【中文标题】使用 ffmpeg 和 libvorbis 编码 webm 不起作用【英文标题】:Encoding webm with ffmpeg and libvorbis does not work 【发布时间】:2014-02-13 23:51:28 【问题描述】:我正在尝试运行 ffmpeg 多路复用示例的修改版本,该示例将 vorbis 编码的音频输出到 webm 容器。
如果我指定 mp3 作为格式,代码可以正常工作,只是在我使用 vorbis 时不行
代码类似于http://www.ffmpeg.org/doxygen/2.0/doc_2examples_2muxing_8c-example.html,但去掉了视频部分。我在启用视频的情况下进行了测试,示例视频已正确编码,但没有音频。
ffmpeg 编译时带有 libvorbis 和 libvpx 支持。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#define STREAM_DURATION 200.0
extern AVCodec ff_libvorbis_encoder;
static AVFrame *frame;
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,
enum AVCodecID codec_id)
AVCodecContext *c;
AVStream *st;
/* find the encoder */
//*codec = &ff_libvorbis_encoder;
*codec = avcodec_find_encoder(codec_id);
if (!(*codec))
fprintf(stderr, "Could not find encoder for '%s'\n",
avcodec_get_name(codec_id));
exit(1);
st = avformat_new_stream(oc, *codec);
if (!st)
fprintf(stderr, "Could not allocate stream\n");
exit(1);
st->id = oc->nb_streams-1;
c = st->codec;
switch ((*codec)->type)
case AVMEDIA_TYPE_AUDIO:
c->sample_fmt = AV_SAMPLE_FMT_FLTP;
c->bit_rate = 64000;
c->sample_rate = 44100;
c->channels = 2;
break;
default:
break;
/* Some formats want stream headers to be separate. */
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
static float t, tincr, tincr2;
static uint8_t **src_samples_data;
static int src_samples_linesize;
static int src_nb_samples;
static int max_dst_nb_samples;
uint8_t **dst_samples_data;
int dst_samples_linesize;
int dst_samples_size;
struct SwrContext *swr_ctx = NULL;
static void open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st)
AVCodecContext *c;
int ret;
c = st->codec;
/* open it */
ret = avcodec_open2(c, codec, NULL);
if (ret sample_rate;
/* increment frequency by 110 Hz per second */
tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
src_nb_samples = c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ?
10000 : c->frame_size;
ret = av_samples_alloc_array_and_samples(&src_samples_data, &src_samples_linesize, c->channels,
src_nb_samples, c->sample_fmt, 0);
if (ret sample_fmt != AV_SAMPLE_FMT_S16)
swr_ctx = swr_alloc();
if (!swr_ctx)
fprintf(stderr, "Could not allocate resampler context\n");
exit(1);
/* set options */
av_opt_set_int (swr_ctx, "in_channel_count", c->channels, 0);
av_opt_set_int (swr_ctx, "in_sample_rate", c->sample_rate, 0);
av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int (swr_ctx, "out_channel_count", c->channels, 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_FLTP, 0);
/* initialize the resampling context */
if ((ret = swr_init(swr_ctx)) channels,
max_dst_nb_samples, c->sample_fmt, 0);
if (ret channels, max_dst_nb_samples,
c->sample_fmt, 0);
static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)
int j, i, v;
int16_t *q;
q = samples;
for (j = 0; j codec;
get_audio_frame((int16_t *)src_samples_data[0], src_nb_samples, c->channels);
/* convert samples from native format to destination codec format, using the resampler */
if (swr_ctx)
/* compute destination number of samples */
dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, c->sample_rate) + src_nb_samples,
c->sample_rate, c->sample_rate, AV_ROUND_UP);
if (dst_nb_samples > max_dst_nb_samples)
av_free(dst_samples_data[0]);
ret = av_samples_alloc(dst_samples_data, &dst_samples_linesize, c->channels,
dst_nb_samples, c->sample_fmt, 0);
if (ret channels, dst_nb_samples,
c->sample_fmt, 0);
/* convert to destination format */
ret = swr_convert(swr_ctx,
dst_samples_data, dst_nb_samples,
(const uint8_t **)src_samples_data, src_nb_samples);
if (ret nb_samples = dst_nb_samples;
avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
dst_samples_data[0], dst_samples_size, 0);
ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet);
if (ret index;
/* Write the compressed frame to the media file. */
ret = av_interleaved_write_frame(oc, &pkt);
if (ret != 0)
fprintf(stderr, "Error while writing audio frame: %s\n",
av_err2str(ret));
exit(1);
avcodec_free_frame(&frame);
static void close_audio(AVFormatContext *oc, AVStream *st)
avcodec_close(st->codec);
av_free(src_samples_data[0]);
av_free(dst_samples_data[0]);
int main(int argc, char *argv[])
AVOutputFormat *fmt;
AVFormatContext *oc;
AVStream *audio_st;
AVCodec *audio_codec;
double audio_time, video_time;
int ret = 0;
const char *input = argv[1];
const char *output = argv[2];
av_register_all();
avformat_alloc_output_context2(&oc, NULL, NULL, output);
if(!oc)
printf("Could not alloc the output context");
return 1;
fmt = oc->oformat;
audio_st = NULL;
if(fmt->audio_codec != AV_CODEC_ID_NONE)
audio_st = add_stream(oc, &audio_codec, fmt->audio_codec);
printf("Started audio stream with codec %s\n", audio_codec->name);
if(audio_st)
open_audio(oc, audio_codec, audio_st);
av_dump_format(oc, 0, output, 1);
if (!(fmt->flags & AVFMT_NOFILE))
ret = avio_open(&oc->pb, output, AVIO_FLAG_WRITE);
if (ret pts = 0;
for (;;)
audio_time = audio_st ? audio_st->pts.val * av_q2d(audio_st->time_base) : 0.0;
if ((!audio_st || audio_time >= STREAM_DURATION))
break;
write_audio_frame(oc, audio_st);
av_write_trailer(oc);
if(audio_st)
close_audio(oc, audio_st);
if(!(fmt->flags & AVFMT_NOFILE))
avio_close(oc->pb);
avformat_free_context(oc);
return 0;
用
编译clang -o converter -lavcodec -lavformat -lavutil -lswresample -lvorbis converter.c
输出
~/v/converter> ./converter test.wav test.webm
Started audio stream with codec libvorbis
Output #0, webm, to 'test.webm':
Stream #0:0: Audio: vorbis (libvorbis), 44100 Hz, 2 channels, fltp, 64 kb/s
[libvorbis @ 0x7fdafb800600] 33 frames left in the queue on closing
【问题讨论】:
【参考方案1】:所以答案是正确设置音频流的 pts 数据。
【讨论】:
是的。这是使用 Vorbis 编码时的常见问题,因为这是 FFMpeg 中唯一不设置音频 PTS 的编码器。 这里有与 WebM/Vorbis 类似的问题。您能否解释一下您最终是如何设置 pts 的?以上是关于使用 ffmpeg 和 libvorbis 编码 webm 不起作用的主要内容,如果未能解决你的问题,请参考以下文章