Skip to content

Instantly share code, notes, and snippets.

@dsdstudio
Forked from yohhoy/ff2cv.cpp
Created February 23, 2019 15:12
Show Gist options
  • Save dsdstudio/80e7a4036fb68d70e5a213b702a6ee71 to your computer and use it in GitHub Desktop.
Save dsdstudio/80e7a4036fb68d70e5a213b702a6ee71 to your computer and use it in GitHub Desktop.

Revisions

  1. @yohhoy yohhoy revised this gist Feb 18, 2016. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions ff2cv.cpp
    Original file line number Diff line number Diff line change
    @@ -28,6 +28,7 @@ int main(int argc, char* argv[])

    // initialize FFmpeg library
    av_register_all();
    // av_log_set_level(AV_LOG_DEBUG);
    int ret;

    // open input file context
  2. @yohhoy yohhoy created this gist Feb 14, 2016.
    142 changes: 142 additions & 0 deletions ff2cv.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,142 @@
    /*
    * Read video frame with FFmpeg and convert to OpenCV image
    *
    * Copyright (c) 2016 yohhoy
    */
    #include <iostream>
    #include <vector>
    // FFmpeg
    extern "C" {
    #include <libavformat/avformat.h>
    #include <libavcodec/avcodec.h>
    #include <libavutil/avutil.h>
    #include <libavutil/pixdesc.h>
    #include <libswscale/swscale.h>
    }
    // OpenCV
    #include <opencv2/core.hpp>
    #include <opencv2/highgui.hpp>


    int main(int argc, char* argv[])
    {
    if (argc < 2) {
    std::cout << "Usage: ff2cv <infile>" << std::endl;
    return 1;
    }
    const char* infile = argv[1];

    // initialize FFmpeg library
    av_register_all();
    int ret;

    // open input file context
    AVFormatContext* inctx = nullptr;
    ret = avformat_open_input(&inctx, infile, nullptr, nullptr);
    if (ret < 0) {
    std::cerr << "fail to avforamt_open_input(\"" << infile << "\"): ret=" << ret;
    return 2;
    }
    // retrive input stream information
    ret = avformat_find_stream_info(inctx, nullptr);
    if (ret < 0) {
    std::cerr << "fail to avformat_find_stream_info: ret=" << ret;
    return 2;
    }

    // find primary video stream
    AVCodec* vcodec = nullptr;
    ret = av_find_best_stream(inctx, AVMEDIA_TYPE_VIDEO, -1, -1, &vcodec, 0);
    if (ret < 0) {
    std::cerr << "fail to av_find_best_stream: ret=" << ret;
    return 2;
    }
    const int vstrm_idx = ret;
    AVStream* vstrm = inctx->streams[vstrm_idx];

    // open video decoder context
    ret = avcodec_open2(vstrm->codec, vcodec, nullptr);
    if (ret < 0) {
    std::cerr << "fail to avcodec_open2: ret=" << ret;
    return 2;
    }

    // print input video stream informataion
    std::cout
    << "infile: " << infile << "\n"
    << "format: " << inctx->iformat->name << "\n"
    << "vcodec: " << vcodec->name << "\n"
    << "size: " << vstrm->codec->width << 'x' << vstrm->codec->height << "\n"
    << "fps: " << av_q2d(vstrm->codec->framerate) << " [fps]\n"
    << "length: " << av_rescale_q(vstrm->duration, vstrm->time_base, {1,1000}) / 1000. << " [sec]\n"
    << "pixfmt: " << av_get_pix_fmt_name(vstrm->codec->pix_fmt) << "\n"
    << "frame: " << vstrm->nb_frames << "\n"
    << std::flush;

    // initialize sample scaler
    const int dst_width = vstrm->codec->width;
    const int dst_height = vstrm->codec->height;
    const AVPixelFormat dst_pix_fmt = AV_PIX_FMT_BGR24;
    SwsContext* swsctx = sws_getCachedContext(
    nullptr, vstrm->codec->width, vstrm->codec->height, vstrm->codec->pix_fmt,
    dst_width, dst_height, dst_pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr);
    if (!swsctx) {
    std::cerr << "fail to sws_getCachedContext";
    return 2;
    }
    std::cout << "output: " << dst_width << 'x' << dst_height << ',' << av_get_pix_fmt_name(dst_pix_fmt) << std::endl;

    // allocate frame buffer for output
    AVFrame* frame = av_frame_alloc();
    std::vector<uint8_t> framebuf(avpicture_get_size(dst_pix_fmt, dst_width, dst_height));
    avpicture_fill(reinterpret_cast<AVPicture*>(frame), framebuf.data(), dst_pix_fmt, dst_width, dst_height);

    // decoding loop
    AVFrame* decframe = av_frame_alloc();
    unsigned nb_frames = 0;
    bool end_of_stream = false;
    int got_pic = 0;
    AVPacket pkt;
    do {
    if (!end_of_stream) {
    // read packet from input file
    ret = av_read_frame(inctx, &pkt);
    if (ret < 0 && ret != AVERROR_EOF) {
    std::cerr << "fail to av_read_frame: ret=" << ret;
    return 2;
    }
    if (ret == 0 && pkt.stream_index != vstrm_idx)
    goto next_packet;
    end_of_stream = (ret == AVERROR_EOF);
    }
    if (end_of_stream) {
    // null packet for bumping process
    av_init_packet(&pkt);
    pkt.data = nullptr;
    pkt.size = 0;
    }
    // decode video frame
    avcodec_decode_video2(vstrm->codec, decframe, &got_pic, &pkt);
    if (!got_pic)
    goto next_packet;
    // convert frame to OpenCV matrix
    sws_scale(swsctx, decframe->data, decframe->linesize, 0, decframe->height, frame->data, frame->linesize);
    {
    cv::Mat image(dst_height, dst_width, CV_8UC3, framebuf.data(), frame->linesize[0]);
    cv::imshow("press ESC to exit", image);
    if (cv::waitKey(1) == 0x1b)
    break;
    }
    std::cout << nb_frames << '\r' << std::flush; // dump progress
    ++nb_frames;
    next_packet:
    av_free_packet(&pkt);
    } while (!end_of_stream || got_pic);
    std::cout << nb_frames << " frames decoded" << std::endl;

    av_frame_free(&decframe);
    av_frame_free(&frame);
    avcodec_close(vstrm->codec);
    avformat_close_input(&inctx);
    return 0;
    }