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