Monday, April 13, 2015

Using ffmpeg in your own MSVC projects

1. download dev build with headers and libs from http://ffmpeg.zeranoe.com/builds/
2. also download shared build because we will need those dll during run-time
3. make headers and libs visible to VC projects
4. add the following defines:


    #define __STDC_CONSTANT_MACROS
    #define __STDC_FORMAT_MACROS









5. some functions that use newer C features are not supported by MS Visual C++ 2012, like the following function call in log_packet(). These are not critical and can be commented out.

printf("pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
           buf1, av_ts2timestr(pkt->pts, time_base),
           buf2, av_ts2timestr(pkt->dts, time_base),
           buf3, av_ts2timestr(pkt->duration, time_base),
           pkt->stream_index);

6. some ffmpeg code directly assigned structure values which also failed in MSVC. the workaround is that we define a temporary variable, and then assign values for each field, and then do the copy.
    AVRational tmp;
    tmp.den = 1; tmp.num = c->sample_rate;
    ost->st->time_base = tmp;

7. remember to always call av_register_all(); otherwise, codec is not found.
8. in doc/example directory, check example code muxing. c for how to output video/audio samples with a container such as AVI.

9. a complete working code that generates MPEG4 AVI based on muxing.c example code is shown below:

    OutputStream video_st = { 0 }, audio_st = { 0 };
    char filename[] = "zz.avi";
    AVOutputFormat *fmt;
    AVFormatContext *oc;
    AVCodec *audio_codec, *video_codec;
    int ret;
    int have_video = 0, have_audio = 0;
    int encode_video = 0, encode_audio = 0;
    AVDictionary *opt = NULL;


    av_register_all();

    avformat_alloc_output_context2(&oc, NULL, NULL, filename);

    if (!oc) {
        printf("Could not deduce output format from file extension.\n");
        exit(1);
    }
 
    fmt = oc->oformat;
    if (fmt->video_codec != AV_CODEC_ID_NONE) {
        add_stream(&video_st, oc, &video_codec, fmt->video_codec);
        have_video = 1;
        encode_video = 1;
    }

     if (have_video)
        open_video(oc, video_codec, &video_st, opt);
     av_dump_format(oc, 0, filename, 1);

    /* open the output file, if needed */
    if (!(fmt->flags & AVFMT_NOFILE)) {
        ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            fprintf(stderr, "Could not open '%s'\n", filename);
            exit(1);
        }
    }

        /* Write the stream header, if any. */
    ret = avformat_write_header(oc, &opt);
    if (ret < 0) {
        fprintf(stderr, "Error occurred when opening output file.\n");
        exit(1);
    }

    while (encode_video) {
        /* 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_video = !write_video_frame(oc, &video_st);
        }
    }
     /* Write the trailer, if any. The trailer must be written before you
     * close the CodecContexts open when you wrote the header; otherwise
     * av_write_trailer() may try to use memory that was freed on
     * av_codec_close(). */
    av_write_trailer(oc);

    /* Close each codec. */
    if (have_video)
        close_stream(oc, &video_st);

    if (!(fmt->flags & AVFMT_NOFILE))
        /* Close the output file. */
        avio_closep(&oc->pb);

    /* free the stream */
    avformat_free_context(oc);

0 Comments:

Post a Comment

<< Home