Commit 76a266f2 authored by Tristan Matthews's avatar Tristan Matthews
Browse files

* #17601: video: send/encode thread uses pthreads instead of cc++ threads

parent ab00551e
......@@ -34,6 +34,6 @@
#include "logger.h"
// If condition A is false, print the error message in M and exit thread
#define EXIT_IF_FAIL(A, M, ...) if (!(A)) { ERROR(M, ##__VA_ARGS__); ost::Thread::exit(); }
#define EXIT_IF_FAIL(A, M, ...) if (!(A)) { ERROR(M, ##__VA_ARGS__); threadRunning_ = false; pthread_exit(NULL); }
#endif // CHECK_H_
......@@ -31,8 +31,8 @@
#include "video_receive_thread.h"
#include "dbus/video_controls.h"
#include "check.h"
#include "packet_handle.h"
#include "logger.h"
// libav includes
extern "C" {
......@@ -73,8 +73,6 @@ const int SDP_BUFFER_SIZE = 8192;
} // end anonymous namespace
#define RETURN_IF_FAIL(A, M, ...) if (!(A)) { ERROR(M, ##__VA_ARGS__); threadRunning_ = false; pthread_exit(NULL); }
void VideoReceiveThread::openDecoder()
{
if (decoderCtx_)
......@@ -86,7 +84,7 @@ void VideoReceiveThread::openDecoder()
#else
int ret = avcodec_open2(decoderCtx_, inputDecoder_, NULL);
#endif
RETURN_IF_FAIL(ret == 0, "Could not open codec");
EXIT_IF_FAIL(ret == 0, "Could not open codec");
}
// We do this setup here instead of the constructor because we don't want the
......@@ -112,7 +110,7 @@ void VideoReceiveThread::setup()
DEBUG("Using %s format", format_str.c_str());
AVInputFormat *file_iformat = av_find_input_format(format_str.c_str());
RETURN_IF_FAIL(file_iformat, "Could not find format \"%s\"", format_str.c_str());
EXIT_IF_FAIL(file_iformat, "Could not find format \"%s\"", format_str.c_str());
AVDictionary *options = NULL;
if (!args_["framerate"].empty())
......@@ -126,7 +124,7 @@ void VideoReceiveThread::setup()
inputCtx_ = avformat_alloc_context();
inputCtx_->interrupt_callback = interruptCb_;
if (input == SDP_FILENAME) {
RETURN_IF_FAIL(not stream_.str().empty(), "No SDP loaded");
EXIT_IF_FAIL(not stream_.str().empty(), "No SDP loaded");
inputCtx_->pb = avioContext_.get();
}
int ret = avformat_open_input(&inputCtx_, input.c_str(), file_iformat, options ? &options : NULL);
......@@ -159,7 +157,7 @@ void VideoReceiveThread::setup()
if (av_strerror(ret, errBuf, sizeof errBuf) < 0)
errBuf[0] = '\0';
// always fail here
RETURN_IF_FAIL(false, "Could not find stream info: %s", errBuf);
EXIT_IF_FAIL(false, "Could not find stream info: %s", errBuf);
}
// find the first video stream from the input
......@@ -167,19 +165,19 @@ void VideoReceiveThread::setup()
if (inputCtx_->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
streamIndex_ = i;
RETURN_IF_FAIL(streamIndex_ != -1, "Could not find video stream");
EXIT_IF_FAIL(streamIndex_ != -1, "Could not find video stream");
// Get a pointer to the codec context for the video stream
decoderCtx_ = inputCtx_->streams[streamIndex_]->codec;
// find the decoder for the video stream
inputDecoder_ = avcodec_find_decoder(decoderCtx_->codec_id);
RETURN_IF_FAIL(inputDecoder_, "Unsupported codec");
EXIT_IF_FAIL(inputDecoder_, "Unsupported codec");
openDecoder();
scaledPicture_ = avcodec_alloc_frame();
RETURN_IF_FAIL(scaledPicture_, "Could not allocate output frame");
EXIT_IF_FAIL(scaledPicture_, "Could not allocate output frame");
if (dstWidth_ == 0 and dstHeight_ == 0) {
dstWidth_ = decoderCtx_->width;
......@@ -189,7 +187,7 @@ void VideoReceiveThread::setup()
// determine required buffer size and allocate buffer
bufferSize_ = getBufferSize(dstWidth_, dstHeight_, VIDEO_RGB_FORMAT);
RETURN_IF_FAIL(sink_.start(), "Cannot start shared memory sink");
EXIT_IF_FAIL(sink_.start(), "Cannot start shared memory sink");
Manager::instance().getVideoControls()->startedDecoding(id_, sink_.openedName(), dstWidth_, dstHeight_);
DEBUG("shm sink started with size %d, width %d and height %d", bufferSize_, dstWidth_, dstHeight_);
}
......
......@@ -191,8 +191,7 @@ void VideoSendThread::setup()
if (ret < 0) {
if (options)
av_dict_free(&options);
ERROR("Could not open input file %s", args_["input"].c_str());
ost::Thread::exit();
EXIT_IF_FAIL(false, "Could not open input file %s", args_["input"].c_str());
}
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 8, 0)
ret = av_find_stream_info(inputCtx_);
......@@ -338,7 +337,7 @@ VideoSendThread::VideoSendThread(const std::map<string, string> &args) :
inputDecoderCtx_(0), rawFrame_(0), scaledPicture_(0),
streamIndex_(-1), outbufSize_(0), encoderCtx_(0), stream_(0),
inputCtx_(0), outputCtx_(0), imgConvertCtx_(0), sdp_(), interruptCb_(),
threadRunning_(false), forceKeyFrame_(0)
threadRunning_(false), forceKeyFrame_(0), thread_()
{
interruptCb_.callback = interruptCb;
interruptCb_.opaque = this;
......@@ -397,9 +396,24 @@ struct VideoTxContextHandle {
VideoSendThread &tx_;
};
void VideoSendThread::run()
void VideoSendThread::start()
{
threadRunning_ = true;
pthread_create(&thread_, NULL, &runCallback, this);
}
void *VideoSendThread::runCallback(void *data)
{
VideoSendThread *context = static_cast<VideoSendThread*>(data);
context->run();
return NULL;
}
void VideoSendThread::run()
{
// We don't want setup() called in the main thread in case it exits or blocks
VideoTxContextHandle handle(*this);
setup();
......@@ -408,15 +422,13 @@ void VideoSendThread::run()
int frameNumber = 0;
while (threadRunning_) {
AVPacket inpacket;
{
int ret = av_read_frame(inputCtx_, &inpacket);
if (ret == AVERROR(EAGAIN))
continue;
else if (ret < 0) {
ERROR("Could not read frame");
threadRunning_ = false;
break;
}
int ret = av_read_frame(inputCtx_, &inpacket);
if (ret == AVERROR(EAGAIN))
continue;
else if (ret < 0) {
ERROR("Could not read frame");
threadRunning_ = false;
break;
}
/* Guarantees that we free the packet allocated by av_read_frame */
......@@ -441,17 +453,13 @@ void VideoSendThread::run()
// Set presentation timestamp on our scaled frame before encoding it
scaledPicture_->pts = frameNumber++;
#ifdef CCPP_PREFIX
if ((int) forceKeyFrame_ > 0) {
#else
if (*forceKeyFrame_ > 0) {
#endif
if (forceKeyFrame_ > 0) {
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(53, 20, 0)
scaledPicture_->pict_type = AV_PICTURE_TYPE_I;
#else
scaledPicture_->pict_type = FF_I_TYPE;
#endif
--forceKeyFrame_;
__sync_fetch_and_sub(&forceKeyFrame_, 1);
}
const int encodedSize = avcodec_encode_video(encoderCtx_, outbuf_,
outbufSize_, scaledPicture_);
......@@ -468,29 +476,21 @@ void VideoSendThread::run()
// rescale pts from encoded video framerate to rtp
// clock rate
if (encoderCtx_->coded_frame->pts != static_cast<int64_t>(AV_NOPTS_VALUE)) {
if (encoderCtx_->coded_frame->pts != static_cast<int64_t>(AV_NOPTS_VALUE))
opkt.pts = av_rescale_q(encoderCtx_->coded_frame->pts,
encoderCtx_->time_base,
stream_->time_base);
} else {
else
opkt.pts = 0;
}
// is it a key frame?
if (encoderCtx_->coded_frame->key_frame)
opkt.flags |= AV_PKT_FLAG_KEY;
opkt.stream_index = stream_->index;
// write the compressed frame in the media file
{
int ret = av_interleaved_write_frame(outputCtx_, &opkt);
if (ret < 0) {
ERROR("av_interleaved_write_frame() error");
threadRunning_ = false;
break;
}
}
yield();
// write the compressed frame to the output
EXIT_IF_FAIL(av_interleaved_write_frame(outputCtx_, &opkt) >= 0,
"interleaved_write_frame failed");
}
}
......@@ -498,12 +498,12 @@ VideoSendThread::~VideoSendThread()
{
// FIXME
threadRunning_ = false;
ost::Thread::terminate();
pthread_join(thread_, NULL);
}
void VideoSendThread::forceKeyFrame()
{
++forceKeyFrame_;
__sync_fetch_and_add(&forceKeyFrame_, 1);
}
} // end namespace sfl_video
......@@ -31,7 +31,6 @@
#ifndef _VIDEO_SEND_THREAD_H_
#define _VIDEO_SEND_THREAD_H_
#include "cc_thread.h"
#include <map>
#include <string>
#include "noncopyable.h"
......@@ -49,7 +48,7 @@ class AVCodec;
namespace sfl_video {
class VideoSendThread : public ost::Thread {
class VideoSendThread {
private:
NON_COPYABLE(VideoSendThread);
void forcePresetX264();
......@@ -78,16 +77,15 @@ class VideoSendThread : public ost::Thread {
std::string sdp_;
AVIOInterruptCB interruptCb_;
bool threadRunning_;
#ifdef CCPP_PREFIX
ost::AtomicCounter forceKeyFrame_;
#else
ucommon::atomic::counter forceKeyFrame_;
#endif
int forceKeyFrame_;
static void *runCallback(void *);
pthread_t thread_;
void run();
friend struct VideoTxContextHandle;
public:
explicit VideoSendThread(const std::map<std::string, std::string> &args);
virtual ~VideoSendThread();
virtual void run();
~VideoSendThread();
void start();
std::string getSDP() const { return sdp_; }
void forceKeyFrame();
};
......
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