[libav-api] Muxing video encoded with x264 and faac

FG home at fgda.pl
Sat Aug 24 20:36:19 CEST 2013


There is a muxing example provided in the libs, but does it really
work with more than a handful of codecs and containers? I would be
interested in creating a libx264- and libfaac-encoded movie in an
mp4/flv/mkv container from custom-generated frames. Therefore I've
downloaded libav and x264 via GIT two weeks ago and tried putting
together a small test program. Limited success so far.

After tweaking the code and changing parameters for countless hours
I am left with movie clips that do not work everywhere. ffplay and
vlc play all (mp4, flv and avi), but vlc doesn't play avi audio.
On second hand, MPC Home Cinema 1.6.7.7114 plays flv and avi, while
there's only audio when playing the mp4 format. The same thing goes
with the Windows Media Player (except that it doesn't support flv).

MPC and WMP had no problems with mp4 videos that I have created with
the current avconv and libx264, so I am sure that there must be
something wrong with my code. Could you look at it and tell me what
should be done to make it work properly? One more thing...
It SEGFAULTs when I try to save to mkv. Does that encoder require
allocating extradata by myself and what should I put there?

Here's the program. Thanks in advance.



// Generate a h264 video and a 220/440Hz alternating AAC tone.

#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavformat/avformat.h>

// Function pointers to encoders: video and audio.
int (*encoders[2])(AVCodecContext*, AVPacket*, const AVFrame*, int*)
     = { avcodec_encode_video2, avcodec_encode_audio2 };

const double duration = 30.0;
const int frame_rate = 24, max_frames = 24 * 30, sample_rate = 44100;
const int frame_width = 640, frame_height = 360;

int encode(AVFormatContext *ctx, AVStream *st, AVFrame *frame) {
     int gotit;
     AVPacket pkt;
     AVCodecContext *cctx = st->codec;
     av_init_packet(&pkt);
     pkt.data = NULL;
     pkt.size = 0;
     pkt.stream_index = st->index;
     int is_audio = st->codec->codec_type == AVMEDIA_TYPE_AUDIO;
     if (frame) {
         long int msecs = 0;
         if (is_audio) msecs = (1000.0 / sample_rate) * frame->pts;
         else msecs = frame->pts * 1000.0 / frame_rate;
         printf("encoding %s frame, PTS %6lld, time: %4ld.%03ld\n",
             (is_audio?"audio":"video"), frame->pts, msecs / 1000, msecs % 1000);
         fflush(stdout);
     }
     if ((encoders[is_audio])(cctx, &pkt, frame, &gotit) < 0) exit(40);
     if (gotit) {
         if (pkt.pts != AV_NOPTS_VALUE)
             pkt.pts = av_rescale_q(pkt.pts, cctx->time_base, st->time_base);
         if (pkt.dts != AV_NOPTS_VALUE)
             pkt.dts = av_rescale_q(pkt.dts, cctx->time_base, st->time_base);
         pkt.stream_index = st->index;
         printf("writing  %s frame, PTS %6lld\n",
             (is_audio?"audio":"video"), pkt.pts);
         fflush(stdout);
         if (av_interleaved_write_frame(ctx, &pkt) < 0) exit(41);
         av_free_packet(&pkt);
     }
     return gotit;
}

int main(int argc, char *argv[]) {
     AVFormatContext *ctx = NULL;
     AVCodecContext *vctx = NULL, *actx = NULL;
     AVCodec *vcodec = NULL, *acodec = NULL;
     AVStream *vstream = NULL, *astream = NULL;
     AVOutputFormat *outformat = NULL;
     uint16_t *samples = NULL;
     AVFrame *vframe = NULL, *aframe = NULL;
     AVDictionary *voptions = NULL;

     int i, j, x, y, gotit, samples_size, frame_nr = 0;
     long long int sample_nr = 0, max_samples;
     double t = 0, tincr = 2 * M_PI * 440.0 / sample_rate;

     if (argc != 2) {
         printf("Missing argument (name of a movie file to create).\n");
         exit(0);
     }
     const char *filename = argv[1];

     av_register_all();
     av_log_set_level(AV_LOG_INFO);
     if (!(vcodec = avcodec_find_encoder_by_name("libx264"))) exit(1);
     if (!(acodec = avcodec_find_encoder_by_name("libfaac"))) exit(2);
     if (!(outformat = av_guess_format(0, filename, 0))) exit(3);
     if (!(ctx = avformat_alloc_context())) exit(4);
     ctx->oformat = outformat;
     snprintf(ctx->filename, sizeof(ctx->filename), "%s", filename);
     if (!(vstream = avformat_new_stream(ctx, vcodec))) exit(5);
     if (!(astream = avformat_new_stream(ctx, acodec))) exit(6);
     vctx = vstream->codec;
     actx = astream->codec;
     vctx->sample_aspect_ratio.num = 1;
     vctx->sample_aspect_ratio.den = 1;

     vctx->width = frame_width;
     vctx->height = frame_height;
     vctx->time_base.num = 1;
     vctx->time_base.den = frame_rate;
     vctx->gop_size = 12;
     vctx->pix_fmt = AV_PIX_FMT_YUV420P;

     actx->bit_rate = 96000;
     actx->sample_fmt = AV_SAMPLE_FMT_S16;
     actx->sample_rate = sample_rate;
     actx->time_base.num = 1;
     actx->time_base.den = sample_rate;
     actx->channel_layout = AV_CH_LAYOUT_STEREO;
     actx->channels = 2;

     av_dict_set(&voptions, "profile", "baseline", 0);
     if (avcodec_open2(vctx, vcodec, &voptions) < 0) exit(7);
     if (avcodec_open2(actx, acodec, 0) < 0) exit(8);
     if (avio_open(&ctx->pb, filename, AVIO_FLAG_WRITE) < 0) exit(9);

     outformat->video_codec = vcodec->id;
     outformat->audio_codec = acodec->id;

     if (ctx->oformat->flags & AVFMT_GLOBALHEADER) {
         vctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
         actx->flags |= CODEC_FLAG_GLOBAL_HEADER;
     }

     if (!(vframe = avcodec_alloc_frame())) exit(11);
     if (!(aframe = avcodec_alloc_frame())) exit(12);
     if (!(av_image_alloc(vframe->data, vframe->linesize, vctx->width,
         vctx->height, vctx->pix_fmt, 32))) exit(13);

     int width = frame_width / frame_rate - 1;
     // Draw grid lines for every frame with "width" spacing.
     for (x = width; x <= frame_rate * width; x += width)
         for (y = 0; y < frame_height; y++)
             vframe->data[0][y * vframe->linesize[0] + x] = 255;

     aframe->nb_samples     = actx->frame_size;
     aframe->format         = actx->sample_fmt;
     aframe->channel_layout = actx->channel_layout;

     samples_size = av_samples_get_buffer_size(NULL, actx->channels,
         actx->frame_size, actx->sample_fmt, 0);
     if (!(samples = (uint16_t*) av_malloc(samples_size))) exit(14);
     if (avcodec_fill_audio_frame(aframe, actx->channels,
             actx->sample_fmt, (const uint8_t*)samples, samples_size, 0) < 0)
         exit(15);

     if (avformat_write_header(ctx, 0)) exit(16);

     printf("audio frame size: %d\n", actx->frame_size);
     max_samples = duration * actx->sample_rate;

     int distance = frame_height / (max_frames * 1.0 / frame_rate + 4);
     for (i = 0; i < max_frames; i++) {
        // Drawing one horizontal bar per second.
         y = distance * (frame_nr / frame_rate + 2);
         for (x = 0; x <= ((frame_nr % frame_rate) + 1) * width; x++) {
             vframe->data[0][y * vframe->linesize[0] + x] = 255;
             vframe->data[0][(y + 1) * vframe->linesize[0] + x] = 255;
             vframe->data[0][(y + 2) * vframe->linesize[0] + x] = 255;
         }
         vframe->pts = frame_nr;
         encode(ctx, vstream, vframe);
         frame_nr++;
     }
     // We are alternating 440Hz and 220Hz tones every second.
     while (sample_nr <= max_samples) {
         int mult = ((sample_nr / actx->sample_rate) % 2 == 0) ? 1 : 2;
         for (j = 0; j < actx->frame_size; j++, sample_nr++) {
             int value = (int)(sin(mult * t) * 10000) / 2;
             samples[2*j] = samples[2*j + 1] = value;
             t += tincr;
         }
         aframe->pts = sample_nr;
         encode(ctx, astream, aframe);
     }
     for (gotit = 1; gotit; ) gotit = encode(ctx, vstream, 0);
     for (gotit = 1; gotit; ) gotit = encode(ctx, astream, 0);
     av_write_trailer(ctx);

     avcodec_close(vctx);
     avcodec_close(actx);
     av_freep(&vframe->data[0]);
     avcodec_free_frame(&vframe);
     avcodec_free_frame(&aframe);
     av_free(vstream);
     av_free(astream);
     av_free(samples);
     avio_close(ctx->pb);
     av_free(ctx);
     printf("Finished!\n");
     return 0;
}




More information about the libav-api mailing list