Commit 11530096 authored by Tristan Matthews's avatar Tristan Matthews

video: implement framerate emulation

Refs #45640

Change-Id: Ia67ae890585c6e3346300b0c0259342c2b686fbe
parent 9210482b
......@@ -31,12 +31,23 @@
#ifndef __LIBAV_DEPS_H__
#define __LIBAV_DEPS_H__
/* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg
* a is the major version
* b and c the minor and micro versions of libav
* d and e the minor and micro versions of FFmpeg */
#define LIBAVFORMAT_VERSION_CHECK( a, b, c, d, e ) \
( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT( a, b, c ) ) || \
(LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT( a, d, e ) ) )
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libavutil/avutil.h>
#if LIBAVFORMAT_VERSION_CHECK(54, 6, 0, 60, 100)
#include <libavutil/time.h>
#endif
#include <libavutil/pixdesc.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h> // for av_rescale_q (old libav support)
......@@ -46,14 +57,6 @@ extern "C" {
#include "libav_utils.h"
/* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg
* a is the major version
* b and c the minor and micro versions of libav
* d and e the minor and micro versions of FFmpeg */
#define LIBAVFORMAT_VERSION_CHECK( a, b, c, d, e ) \
( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT( a, b, c ) ) || \
(LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT( a, d, e ) ) )
/* LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg
* a is the major version
* b and c the minor and micro versions of libav
......
......@@ -45,6 +45,9 @@ VideoDecoder::VideoDecoder() :
, decoderCtx_(0)
, inputCtx_(avformat_alloc_context())
, streamIndex_(-1)
, emulateRate_(false)
, startTime_(AV_NOPTS_VALUE)
, lastDts_(AV_NOPTS_VALUE)
{
}
......@@ -158,6 +161,10 @@ int VideoDecoder::setupFromVideoData()
}
decoderCtx_->thread_count = 1;
if (emulateRate_) {
DEBUG("Using framerate emulation");
startTime_ = av_gettime();
}
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 6, 0)
ret = avcodec_open(decoderCtx_, inputDecoder_);
......@@ -174,6 +181,19 @@ int VideoDecoder::setupFromVideoData()
int VideoDecoder::decode(VideoFrame& result)
{
if (emulateRate_) {
const int64_t pts = av_rescale(lastDts_, 1000000, AV_TIME_BASE);
const int64_t now = av_gettime() - startTime_;
if (pts > now) {
#if LIBAVFORMAT_VERSION_CHECK(54, 6, 0, 60, 100)
av_usleep(10000);
#else
usleep(10000);
#endif
return 0;
}
}
// Guarantee that we free the packet every iteration
VideoPacket video_packet;
AVPacket *inpacket = video_packet.get();
......@@ -191,6 +211,9 @@ int VideoDecoder::decode(VideoFrame& result)
if (inpacket->stream_index != streamIndex_)
return 0;
if (inpacket->dts != AV_NOPTS_VALUE)
lastDts_ = av_rescale_q(inpacket->dts, decoderCtx_->time_base, AV_TIME_BASE_Q);
int frameFinished = 0;
int len = avcodec_decode_video2(decoderCtx_, result.get(),
&frameFinished, inpacket);
......
......@@ -50,6 +50,7 @@ namespace sfl_video {
VideoDecoder();
~VideoDecoder();
void emulateRate() { emulateRate_ = true; }
void setInterruptCallback(int (*cb)(void*), void *opaque);
void setIOContext(VideoIOHandle *ioctx);
int openInput(const std::string &source_str,
......@@ -69,6 +70,9 @@ namespace sfl_video {
AVCodecContext *decoderCtx_;
AVFormatContext *inputCtx_;
int streamIndex_;
bool emulateRate_;
int64_t startTime_;
int64_t lastDts_;
};
}
......
......@@ -64,6 +64,7 @@ VideoInput::VideoInput(const std::map<std::string, std::string>& map) :
, channel_(extract(map, "channel"))
, framerate_(extract(map, "framerate"))
, video_size_(extract(map, "video_size"))
, emulateRate_(map.find("emulate_rate") != map.end())
{
DEBUG("initializing video input with: "
"mirror: %s, "
......@@ -72,12 +73,14 @@ VideoInput::VideoInput(const std::map<std::string, std::string>& map) :
"channel: '%s', "
"framerate: '%s', "
"video_size: '%s'",
"emulate_rate: '%s'",
mirror_ ? "yes" : "no",
input_.c_str(),
format_.c_str(),
channel_.c_str(),
framerate_.c_str(),
video_size_.c_str());
video_size_.c_str(),
emulateRate_ ? "yes" : "no");
start();
}
......@@ -100,6 +103,8 @@ bool VideoInput::setup()
decoder_->setOption("channel", channel_.c_str());
if (!loop_.empty())
decoder_->setOption("loop", loop_.c_str());
if (emulateRate_)
decoder_->emulateRate();
decoder_->setInterruptCallback(interruptCb, this);
......
......@@ -73,6 +73,7 @@ private:
std::string channel_;
std::string framerate_;
std::string video_size_;
bool emulateRate_;
// as SFLThread
bool setup();
......
......@@ -130,6 +130,8 @@ initFile(std::string path)
map["format"] = "image2";
map["framerate"] = "1";
map["loop"] = "1";
// Not internally used by libavcodec, just our VideoDecoder
map["emulate_rate"] = "1";
}
return map;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment