exit(1);
}
- ost->st = avformat_new_stream(oc, *codec);
+ ost->st = avformat_new_stream(oc, NULL);
if (!ost->st) {
- fprintf(stderr, "Could not alloc stream\n");
+ fprintf(stderr, "Could not allocate stream\n");
exit(1);
}
-
- c = avcodec_alloc_context3(codec);
+ ost->st->id = oc->nb_streams-1;
- c = ost->st->codec;
++ c = avcodec_alloc_context3(*codec);
+ if (!c) {
+ fprintf(stderr, "Could not alloc an encoding context\n");
+ exit(1);
+ }
+ ost->enc = c;
- /* put sample parameters */
- c->sample_fmt = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_S16;
- c->sample_rate = codec->supported_samplerates ? codec->supported_samplerates[0] : 44100;
- c->channel_layout = codec->channel_layouts ? codec->channel_layouts[0] : AV_CH_LAYOUT_STEREO;
- c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
- c->bit_rate = 64000;
+ switch ((*codec)->type) {
+ case AVMEDIA_TYPE_AUDIO:
+ c->sample_fmt = (*codec)->sample_fmts ?
+ (*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
+ c->bit_rate = 64000;
+ c->sample_rate = 44100;
+ if ((*codec)->supported_samplerates) {
+ c->sample_rate = (*codec)->supported_samplerates[0];
+ for (i = 0; (*codec)->supported_samplerates[i]; i++) {
+ if ((*codec)->supported_samplerates[i] == 44100)
+ c->sample_rate = 44100;
+ }
+ }
+ c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
+ c->channel_layout = AV_CH_LAYOUT_STEREO;
+ if ((*codec)->channel_layouts) {
+ c->channel_layout = (*codec)->channel_layouts[0];
+ for (i = 0; (*codec)->channel_layouts[i]; i++) {
+ if ((*codec)->channel_layouts[i] == AV_CH_LAYOUT_STEREO)
+ c->channel_layout = AV_CH_LAYOUT_STEREO;
+ }
+ }
+ c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
+ ost->st->time_base = (AVRational){ 1, c->sample_rate };
+ break;
+
+ case AVMEDIA_TYPE_VIDEO:
+ c->codec_id = codec_id;
+
+ c->bit_rate = 400000;
+ /* Resolution must be a multiple of two. */
+ c->width = 352;
+ c->height = 288;
+ /* timebase: This is the fundamental unit of time (in seconds) in terms
+ * of which frame timestamps are represented. For fixed-fps content,
+ * timebase should be 1/framerate and timestamp increments should be
+ * identical to 1. */
+ ost->st->time_base = (AVRational){ 1, STREAM_FRAME_RATE };
+ c->time_base = ost->st->time_base;
+
+ c->gop_size = 12; /* emit one intra frame every twelve frames at most */
+ c->pix_fmt = STREAM_PIX_FMT;
+ if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
+ /* just for testing, we also add B frames */
+ c->max_b_frames = 2;
+ }
+ if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
+ /* Needed to avoid using macroblocks in which some coeffs overflow.
+ * This does not happen with normal video, it just happens here as
+ * the motion of the chroma plane does not match the luma plane. */
+ c->mb_decision = 2;
+ }
+ break;
- ost->st->time_base = (AVRational){ 1, c->sample_rate };
+ default:
+ break;
+ }
- // some formats want stream headers to be separate
+ /* Some formats want stream headers to be separate. */
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
-
- /* initialize sample format conversion;
- * to simplify the code, we always pass the data through lavr, even
- * if the encoder supports the generated format directly -- the price is
- * some extra data copying;
- */
- ost->avr = avresample_alloc_context();
- if (!ost->avr) {
- fprintf(stderr, "Error allocating the resampling context\n");
- exit(1);
- }
-
- av_opt_set_int(ost->avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
- av_opt_set_int(ost->avr, "in_sample_rate", 44100, 0);
- av_opt_set_int(ost->avr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
- av_opt_set_int(ost->avr, "out_sample_fmt", c->sample_fmt, 0);
- av_opt_set_int(ost->avr, "out_sample_rate", c->sample_rate, 0);
- av_opt_set_int(ost->avr, "out_channel_layout", c->channel_layout, 0);
-
- ret = avresample_open(ost->avr);
- if (ret < 0) {
- fprintf(stderr, "Error opening the resampling context\n");
- exit(1);
- }
}
+/**************************************************************/
+/* audio output */
+
static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
uint64_t channel_layout,
int sample_rate, int nb_samples)
return frame;
}
-static void open_audio(AVFormatContext *oc, OutputStream *ost)
+static void open_audio(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
{
AVCodecContext *c;
- int nb_samples, ret;
+ int nb_samples;
+ int ret;
+ AVDictionary *opt = NULL;
- c = ost->st->codec;
+ c = ost->enc;
/* open it */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ av_dict_copy(&opt, opt_arg, 0);
+ ret = avcodec_open2(c, codec, &opt);
+ av_dict_free(&opt);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret));
exit(1);
}
ost->frame = alloc_audio_frame(c->sample_fmt, c->channel_layout,
c->sample_rate, nb_samples);
- ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, AV_CH_LAYOUT_STEREO,
- 44100, nb_samples);
+ ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, c->channel_layout,
+ c->sample_rate, nb_samples);
+ /* copy the stream parameters to the muxer */
+ ret = avcodec_parameters_from_context(ost->st->codecpar, c);
+ if (ret < 0) {
+ fprintf(stderr, "Could not copy the stream parameters\n");
+ exit(1);
+ }
++
+ /* create resampler context */
+ ost->swr_ctx = swr_alloc();
+ if (!ost->swr_ctx) {
+ fprintf(stderr, "Could not allocate resampler context\n");
+ exit(1);
+ }
+
+ /* set options */
+ av_opt_set_int (ost->swr_ctx, "in_channel_count", c->channels, 0);
+ av_opt_set_int (ost->swr_ctx, "in_sample_rate", c->sample_rate, 0);
+ av_opt_set_sample_fmt(ost->swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+ av_opt_set_int (ost->swr_ctx, "out_channel_count", c->channels, 0);
+ av_opt_set_int (ost->swr_ctx, "out_sample_rate", c->sample_rate, 0);
+ av_opt_set_sample_fmt(ost->swr_ctx, "out_sample_fmt", c->sample_fmt, 0);
+
+ /* initialize the resampling context */
+ if ((ret = swr_init(ost->swr_ctx)) < 0) {
+ fprintf(stderr, "Failed to initialize the resampling context\n");
+ exit(1);
+ }
}
/* Prepare a 16 bit dummy audio frame of 'frame_size' samples and
STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
return NULL;
-
- for (j = 0; j < frame->nb_samples; j++) {
+ for (j = 0; j <frame->nb_samples; j++) {
v = (int)(sin(ost->t) * 10000);
- for (i = 0; i < ost->st->codec->channels; i++)
+ for (i = 0; i < ost->enc->channels; i++)
*q++ = v;
ost->t += ost->tincr;
ost->tincr += ost->tincr2;
* encode one audio frame and send it to the muxer
* return 1 when encoding is finished, 0 otherwise
*/
-static int process_audio_stream(AVFormatContext *oc, OutputStream *ost)
+static int write_audio_frame(AVFormatContext *oc, OutputStream *ost)
{
+ AVCodecContext *c;
+ AVPacket pkt = { 0 }; // data and size must be 0;
AVFrame *frame;
- int got_output = 0;
int ret;
- c = ost->st->codec;
+ int got_packet;
+ int dst_nb_samples;
+
+ av_init_packet(&pkt);
++ c = ost->enc;
frame = get_audio_frame(ost);
- got_output |= !!frame;
- /* feed the data to lavr */
if (frame) {
- ret = avresample_convert(ost->avr, NULL, 0, 0,
- frame->extended_data, frame->linesize[0],
- frame->nb_samples);
- if (ret < 0) {
- fprintf(stderr, "Error feeding audio data to the resampler\n");
- exit(1);
- }
- }
+ /* convert samples from native format to destination codec format, using the resampler */
+ /* compute destination number of samples */
+ dst_nb_samples = av_rescale_rnd(swr_get_delay(ost->swr_ctx, c->sample_rate) + frame->nb_samples,
+ c->sample_rate, c->sample_rate, AV_ROUND_UP);
+ av_assert0(dst_nb_samples == frame->nb_samples);
- while ((frame && avresample_available(ost->avr) >= ost->frame->nb_samples) ||
- (!frame && avresample_get_out_samples(ost->avr, 0))) {
/* when we pass a frame to the encoder, it may keep a reference to it
* internally;
* make sure we do not overwrite it here
return picture;
}
-static void open_video(AVFormatContext *oc, OutputStream *ost)
+static void open_video(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
{
- AVCodecContext *c;
int ret;
- AVCodecContext *c = ost->st->codec;
++ AVCodecContext *c = ost->enc;
+ AVDictionary *opt = NULL;
- c = ost->enc;
+ av_dict_copy(&opt, opt_arg, 0);
/* open the codec */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
+ ret = avcodec_open2(c, codec, &opt);
+ av_dict_free(&opt);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret));
exit(1);
}
int ret;
AVCodecContext *c;
AVFrame *frame;
- AVPacket pkt = { 0 };
int got_packet = 0;
+ AVPacket pkt = { 0 };
- c = ost->st->codec;
+ c = ost->enc;
frame = get_video_frame(ost);
while (encode_video || encode_audio) {
/* select the stream to encode */
if (encode_video &&
- (!encode_audio || av_compare_ts(video_st.next_pts, video_st.st->codec->time_base,
- audio_st.next_pts, audio_st.st->codec->time_base) <= 0)) {
+ (!encode_audio || av_compare_ts(video_st.next_pts, video_st.enc->time_base,
+ audio_st.next_pts, audio_st.enc->time_base) <= 0)) {
encode_video = !write_video_frame(oc, &video_st);
} else {
- encode_audio = !process_audio_stream(oc, &audio_st);
+ encode_audio = !write_audio_frame(oc, &audio_st);
}
}