aboutsummaryrefslogtreecommitdiffstats
path: root/examples/alffplay.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2018-01-01 18:47:48 -0800
committerChris Robinson <[email protected]>2018-01-01 18:47:48 -0800
commitaecfa0b4269f927f778a4cece741b4937a4b4f6b (patch)
treeddff865e58aaa2f137fea31c9b813aa01e26ec47 /examples/alffplay.cpp
parent9675068706acadb9e6a5dc3ef483271b25e9a165 (diff)
Make smart pointer wrappers for some ffmpeg types
Diffstat (limited to 'examples/alffplay.cpp')
-rw-r--r--examples/alffplay.cpp153
1 files changed, 81 insertions, 72 deletions
diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp
index b507101b..9f6a1aec 100644
--- a/examples/alffplay.cpp
+++ b/examples/alffplay.cpp
@@ -85,6 +85,32 @@ enum class SyncMaster {
inline microseconds get_avtime()
{ return microseconds(av_gettime()); }
+/* Define unique_ptrs to auto-cleanup associated ffmpeg objects. */
+struct AVFormatCtxDeleter {
+ void operator()(AVFormatContext *ptr) { avformat_close_input(&ptr); }
+};
+using AVFormatCtxPtr = std::unique_ptr<AVFormatContext,AVFormatCtxDeleter>;
+
+struct AVCodecCtxDeleter {
+ void operator()(AVCodecContext *ptr) { avcodec_free_context(&ptr); }
+};
+using AVCodecCtxPtr = std::unique_ptr<AVCodecContext,AVCodecCtxDeleter>;
+
+struct AVFrameDeleter {
+ void operator()(AVFrame *ptr) { av_frame_free(&ptr); }
+};
+using AVFramePtr = std::unique_ptr<AVFrame,AVFrameDeleter>;
+
+struct SwrContextDeleter {
+ void operator()(SwrContext *ptr) { swr_free(&ptr); }
+};
+using SwrContextPtr = std::unique_ptr<SwrContext,SwrContextDeleter>;
+
+struct SwsContextDeleter {
+ void operator()(SwsContext *ptr) { sws_freeContext(ptr); }
+};
+using SwsContextPtr = std::unique_ptr<SwsContext,SwsContextDeleter>;
+
class PacketQueue {
std::deque<AVPacket> mPackets;
@@ -132,7 +158,7 @@ struct AudioState {
MovieState &mMovie;
AVStream *mStream{nullptr};
- AVCodecContext *mCodecCtx{nullptr};
+ AVCodecCtxPtr mCodecCtx;
std::mutex mQueueMtx;
std::condition_variable mQueueCond;
@@ -144,8 +170,8 @@ struct AudioState {
nanoseconds mCurrentPts{0};
/* Decompressed sample frame, and swresample context for conversion */
- AVFrame *mDecodedFrame{nullptr};
- struct SwrContext *mSwresCtx{nullptr};
+ AVFramePtr mDecodedFrame;
+ SwrContextPtr mSwresCtx;
/* Conversion format, for what gets fed to Alure */
int mDstChanLayout{0};
@@ -175,12 +201,7 @@ struct AudioState {
if(!mBuffers.empty())
alDeleteBuffers(mBuffers.size(), mBuffers.data());
- av_frame_free(&mDecodedFrame);
- swr_free(&mSwresCtx);
-
av_freep(&mSamples);
-
- avcodec_free_context(&mCodecCtx);
}
nanoseconds getClock();
@@ -196,7 +217,7 @@ struct VideoState {
MovieState &mMovie;
AVStream *mStream{nullptr};
- AVCodecContext *mCodecCtx{nullptr};
+ AVCodecCtxPtr mCodecCtx;
std::mutex mQueueMtx;
std::condition_variable mQueueCond;
@@ -210,8 +231,8 @@ struct VideoState {
microseconds mCurrentPtsTime{0};
/* Decompressed video frame, and swscale context for conversion */
- AVFrame *mDecodedFrame{nullptr};
- struct SwsContext *mSwscaleCtx{nullptr};
+ AVFramePtr mDecodedFrame;
+ SwsContextPtr mSwscaleCtx;
struct Picture {
SDL_Texture *mImage{nullptr};
@@ -235,13 +256,6 @@ struct VideoState {
std::atomic<bool> mFinalUpdate{false};
VideoState(MovieState &movie) : mMovie(movie) { }
- ~VideoState()
- {
- sws_freeContext(mSwscaleCtx);
- mSwscaleCtx = nullptr;
- av_frame_free(&mDecodedFrame);
- avcodec_free_context(&mCodecCtx);
- }
nanoseconds getClock();
@@ -256,7 +270,7 @@ struct VideoState {
};
struct MovieState {
- AVFormatContext *mFormatCtx{nullptr};
+ AVFormatCtxPtr mFormatCtx;
SyncMaster mAVSyncType{SyncMaster::Default};
@@ -286,7 +300,6 @@ struct MovieState {
mQuit = true;
if(mParseThread.joinable())
mParseThread.join();
- avformat_close_input(&mFormatCtx);
}
static int decode_interrupt_cb(void *ctx);
@@ -400,7 +413,7 @@ int AudioState::decodeFrame()
while(!mMovie.mQuit.load(std::memory_order_relaxed))
{
std::unique_lock<std::mutex> lock(mQueueMtx);
- int ret = avcodec_receive_frame(mCodecCtx, mDecodedFrame);
+ int ret = avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get());
if(ret == AVERROR(EAGAIN))
{
mMovie.mSendDataGood.clear(std::memory_order_relaxed);
@@ -408,7 +421,7 @@ int AudioState::decodeFrame()
mMovie.mSendCond.notify_one();
do {
mQueueCond.wait(lock);
- ret = avcodec_receive_frame(mCodecCtx, mDecodedFrame);
+ ret = avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get());
} while(ret == AVERROR(EAGAIN));
}
lock.unlock();
@@ -423,12 +436,12 @@ int AudioState::decodeFrame()
if(mDecodedFrame->nb_samples <= 0)
{
- av_frame_unref(mDecodedFrame);
+ av_frame_unref(mDecodedFrame.get());
continue;
}
/* If provided, update w/ pts */
- int64_t pts = av_frame_get_best_effort_timestamp(mDecodedFrame);
+ int64_t pts = av_frame_get_best_effort_timestamp(mDecodedFrame.get());
if(pts != AV_NOPTS_VALUE)
mCurrentPts = std::chrono::duration_cast<nanoseconds>(
seconds_d64(av_q2d(mStream->time_base)*pts)
@@ -444,11 +457,11 @@ int AudioState::decodeFrame()
mSamplesMax = mDecodedFrame->nb_samples;
}
/* Return the amount of sample frames converted */
- int data_size = swr_convert(mSwresCtx, &mSamples, mDecodedFrame->nb_samples,
+ int data_size = swr_convert(mSwresCtx.get(), &mSamples, mDecodedFrame->nb_samples,
(const uint8_t**)mDecodedFrame->data, mDecodedFrame->nb_samples
);
- av_frame_unref(mDecodedFrame);
+ av_frame_unref(mDecodedFrame.get());
return data_size;
}
@@ -665,20 +678,21 @@ int AudioState::handler()
mSamplesPos = 0;
mSamplesLen = 0;
- if(!(mDecodedFrame=av_frame_alloc()))
+ mDecodedFrame.reset(av_frame_alloc());
+ if(!mDecodedFrame)
{
std::cerr<< "Failed to allocate audio frame" <<std::endl;
goto finish;
}
- mSwresCtx = swr_alloc_set_opts(nullptr,
+ mSwresCtx.reset(swr_alloc_set_opts(nullptr,
mDstChanLayout, mDstSampleFmt, mCodecCtx->sample_rate,
mCodecCtx->channel_layout ? mCodecCtx->channel_layout :
(uint64_t)av_get_default_channel_layout(mCodecCtx->channels),
mCodecCtx->sample_fmt, mCodecCtx->sample_rate,
0, nullptr
- );
- if(!mSwresCtx || swr_init(mSwresCtx) != 0)
+ ));
+ if(!mSwresCtx || swr_init(mSwresCtx.get()) != 0)
{
std::cerr<< "Failed to initialize audio converter" <<std::endl;
goto finish;
@@ -754,9 +768,6 @@ finish:
alSourceRewind(mSource);
alSourcei(mSource, AL_BUFFER, 0);
- av_frame_free(&mDecodedFrame);
- swr_free(&mSwresCtx);
-
av_freep(&mSamples);
return 0;
@@ -953,7 +964,7 @@ void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer)
if(vp->mImage)
{
- AVFrame *frame = mDecodedFrame;
+ AVFrame *frame = mDecodedFrame.get();
void *pixels = nullptr;
int pitch = 0;
@@ -974,12 +985,11 @@ void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer)
int h = mCodecCtx->height;
if(!mSwscaleCtx || fmt_updated)
{
- sws_freeContext(mSwscaleCtx);
- mSwscaleCtx = sws_getContext(
+ mSwscaleCtx.reset(sws_getContext(
w, h, mCodecCtx->pix_fmt,
w, h, AV_PIX_FMT_YUV420P, 0,
nullptr, nullptr, nullptr
- );
+ ));
}
/* point pict at the queue */
@@ -993,7 +1003,7 @@ void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer)
pict_linesize[1] = pitch / 2;
pict_linesize[2] = pitch / 2;
- sws_scale(mSwscaleCtx, (const uint8_t**)frame->data,
+ sws_scale(mSwscaleCtx.get(), (const uint8_t**)frame->data,
frame->linesize, 0, h, pict_data, pict_linesize);
SDL_UnlockTexture(vp->mImage);
}
@@ -1058,12 +1068,12 @@ nanoseconds VideoState::synchronize(nanoseconds pts)
int VideoState::handler()
{
- mDecodedFrame = av_frame_alloc();
+ mDecodedFrame.reset(av_frame_alloc());
while(!mMovie.mQuit.load(std::memory_order_relaxed))
{
std::unique_lock<std::mutex> lock(mQueueMtx);
/* Decode video frame */
- int ret = avcodec_receive_frame(mCodecCtx, mDecodedFrame);
+ int ret = avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get());
if(ret == AVERROR(EAGAIN))
{
mMovie.mSendDataGood.clear(std::memory_order_relaxed);
@@ -1071,7 +1081,7 @@ int VideoState::handler()
mMovie.mSendCond.notify_one();
do {
mQueueCond.wait(lock);
- ret = avcodec_receive_frame(mCodecCtx, mDecodedFrame);
+ ret = avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get());
} while(ret == AVERROR(EAGAIN));
}
lock.unlock();
@@ -1084,16 +1094,15 @@ int VideoState::handler()
continue;
}
- int64_t ts = av_frame_get_best_effort_timestamp(mDecodedFrame);
+ int64_t ts = av_frame_get_best_effort_timestamp(mDecodedFrame.get());
auto pts = synchronize(
std::chrono::duration_cast<nanoseconds>(seconds_d64(av_q2d(mStream->time_base)*ts))
);
if(queuePicture(pts) < 0)
break;
- av_frame_unref(mDecodedFrame);
+ av_frame_unref(mDecodedFrame.get());
}
mEOS = true;
- av_frame_free(&mDecodedFrame);
std::unique_lock<std::mutex> lock(mPictQMutex);
if(mMovie.mQuit.load(std::memory_order_relaxed))
@@ -1116,25 +1125,29 @@ int MovieState::decode_interrupt_cb(void *ctx)
bool MovieState::prepare()
{
- mFormatCtx = avformat_alloc_context();
- mFormatCtx->interrupt_callback.callback = decode_interrupt_cb;
- mFormatCtx->interrupt_callback.opaque = this;
- if(avio_open2(&mFormatCtx->pb, mFilename.c_str(), AVIO_FLAG_READ,
- &mFormatCtx->interrupt_callback, nullptr))
+ AVIOContext *avioctx = nullptr;
+ AVIOInterruptCB intcb = { decode_interrupt_cb, this };
+ if(avio_open2(&avioctx, mFilename.c_str(), AVIO_FLAG_READ, &intcb, nullptr))
{
std::cerr<< "Failed to open "<<mFilename <<std::endl;
return false;
}
- /* Open movie file */
- if(avformat_open_input(&mFormatCtx, mFilename.c_str(), nullptr, nullptr) != 0)
+ /* Open movie file. If avformat_open_input fails it will automatically free
+ * this context, so don't set it onto a smart pointer yet.
+ */
+ AVFormatContext *fmtctx = avformat_alloc_context();
+ fmtctx->pb = avioctx;
+ fmtctx->interrupt_callback = intcb;
+ if(avformat_open_input(&fmtctx, mFilename.c_str(), nullptr, nullptr) != 0)
{
std::cerr<< "Failed to open "<<mFilename <<std::endl;
return false;
}
+ mFormatCtx.reset(fmtctx);
/* Retrieve stream information */
- if(avformat_find_stream_info(mFormatCtx, nullptr) < 0)
+ if(avformat_find_stream_info(mFormatCtx.get(), nullptr) < 0)
{
std::cerr<< mFilename<<": failed to find stream info" <<std::endl;
return false;
@@ -1181,21 +1194,17 @@ int MovieState::streamComponentOpen(int stream_index)
/* Get a pointer to the codec context for the stream, and open the
* associated codec.
*/
- AVCodecContext *avctx = avcodec_alloc_context3(nullptr);
+ AVCodecCtxPtr avctx(avcodec_alloc_context3(nullptr));
if(!avctx) return -1;
- if(avcodec_parameters_to_context(avctx, mFormatCtx->streams[stream_index]->codecpar))
- {
- avcodec_free_context(&avctx);
+ if(avcodec_parameters_to_context(avctx.get(), mFormatCtx->streams[stream_index]->codecpar))
return -1;
- }
AVCodec *codec = avcodec_find_decoder(avctx->codec_id);
- if(!codec || avcodec_open2(avctx, codec, nullptr) < 0)
+ if(!codec || avcodec_open2(avctx.get(), codec, nullptr) < 0)
{
std::cerr<< "Unsupported codec: "<<avcodec_get_name(avctx->codec_id)
<< " (0x"<<std::hex<<avctx->codec_id<<std::dec<<")" <<std::endl;
- avcodec_free_context(&avctx);
return -1;
}
@@ -1204,14 +1213,14 @@ int MovieState::streamComponentOpen(int stream_index)
{
case AVMEDIA_TYPE_AUDIO:
mAudio.mStream = mFormatCtx->streams[stream_index];
- mAudio.mCodecCtx = avctx;
+ mAudio.mCodecCtx = std::move(avctx);
mAudioThread = std::thread(std::mem_fn(&AudioState::handler), &mAudio);
break;
case AVMEDIA_TYPE_VIDEO:
mVideo.mStream = mFormatCtx->streams[stream_index];
- mVideo.mCodecCtx = avctx;
+ mVideo.mCodecCtx = std::move(avctx);
mVideo.mCurrentPtsTime = get_avtime();
mVideo.mFrameTimer = mVideo.mCurrentPtsTime;
@@ -1221,7 +1230,6 @@ int MovieState::streamComponentOpen(int stream_index)
break;
default:
- avcodec_free_context(&avctx);
return -1;
}
@@ -1234,14 +1242,15 @@ int MovieState::parse_handler()
int audio_index = -1;
/* Dump information about file onto standard error */
- av_dump_format(mFormatCtx, 0, mFilename.c_str(), 0);
+ av_dump_format(mFormatCtx.get(), 0, mFilename.c_str(), 0);
/* Find the first video and audio streams */
for(unsigned int i = 0;i < mFormatCtx->nb_streams;i++)
{
- if(mFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0)
+ auto codecpar = mFormatCtx->streams[i]->codecpar;
+ if(codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0)
video_index = i;
- else if(mFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0)
+ else if(codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0)
audio_index = i;
}
/* Start the external clock in 50ms, to give the audio and video
@@ -1264,7 +1273,7 @@ int MovieState::parse_handler()
while(!mQuit.load(std::memory_order_relaxed) && !input_finished)
{
AVPacket packet;
- if(av_read_frame(mFormatCtx, &packet) < 0)
+ if(av_read_frame(mFormatCtx.get(), &packet) < 0)
input_finished = true;
else
{
@@ -1283,7 +1292,7 @@ int MovieState::parse_handler()
std::unique_lock<std::mutex> lock(mAudio.mQueueMtx);
int ret;
do {
- ret = avcodec_send_packet(mAudio.mCodecCtx, audio_queue.front());
+ ret = avcodec_send_packet(mAudio.mCodecCtx.get(), audio_queue.front());
if(ret != AVERROR(EAGAIN)) audio_queue.pop();
} while(ret != AVERROR(EAGAIN) && !audio_queue.empty());
lock.unlock();
@@ -1294,7 +1303,7 @@ int MovieState::parse_handler()
std::unique_lock<std::mutex> lock(mVideo.mQueueMtx);
int ret;
do {
- ret = avcodec_send_packet(mVideo.mCodecCtx, video_queue.front());
+ ret = avcodec_send_packet(mVideo.mCodecCtx.get(), video_queue.front());
if(ret != AVERROR(EAGAIN)) video_queue.pop();
} while(ret != AVERROR(EAGAIN) && !video_queue.empty());
lock.unlock();
@@ -1317,17 +1326,17 @@ int MovieState::parse_handler()
/* Pass a null packet to finish the send buffers (the receive functions
* will get AVERROR_EOF when emptied).
*/
- if(mVideo.mCodecCtx != nullptr)
+ if(mVideo.mCodecCtx)
{
{ std::lock_guard<std::mutex> lock(mVideo.mQueueMtx);
- avcodec_send_packet(mVideo.mCodecCtx, nullptr);
+ avcodec_send_packet(mVideo.mCodecCtx.get(), nullptr);
}
mVideo.mQueueCond.notify_one();
}
- if(mAudio.mCodecCtx != nullptr)
+ if(mAudio.mCodecCtx)
{
{ std::lock_guard<std::mutex> lock(mAudio.mQueueMtx);
- avcodec_send_packet(mAudio.mCodecCtx, nullptr);
+ avcodec_send_packet(mAudio.mCodecCtx.get(), nullptr);
}
mAudio.mQueueCond.notify_one();
}