裸指针包装
struct AVIOContextDeleter {
void operator()(AVIOContext *ptr) { avio_closep(&ptr); }
};
using AVIOContextPtr = std::unique_ptr<AVIOContext,AVIOContextDeleter>;
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 AVPacketDeleter {
void operator()(AVPacket *pkt) { av_packet_free(&pkt); }
};
using AVPacketPtr = std::unique_ptr<AVPacket,AVPacketDeleter>;
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>;
对象
struct ChannelLayout : public AVChannelLayout {
ChannelLayout() : AVChannelLayout{} { }
~ChannelLayout() { av_channel_layout_uninit(this); }
};
智能指针使用和轮子—解包队列
template<size_t SizeLimit>
class DataQueue {
std::mutex mPacketMutex, mFrameMutex;
std::condition_variable mPacketCond;
std::condition_variable mInFrameCond, mOutFrameCond;
std::deque<AVPacketPtr> mPackets;
size_t mTotalSize{0};
bool mFinished{false};
AVPacketPtr getPacket()
{
std::unique_lock<std::mutex> plock{mPacketMutex};
while(mPackets.empty() && !mFinished)
mPacketCond.wait(plock);
if(mPackets.empty())
return nullptr;
auto ret = std::move(mPackets.front());
mPackets.pop_front();
mTotalSize -= static_cast<unsigned int>(ret->size);
return ret;
}
public:
int sendPacket(AVCodecContext *codecctx)
{
AVPacketPtr packet{getPacket()};
int ret{};
{
std::unique_lock<std::mutex> flock{mFrameMutex};
while((ret=avcodec_send_packet(codecctx, packet.get())) == AVERROR(EAGAIN))
mInFrameCond.wait_for(flock, milliseconds{50});
}
mOutFrameCond.notify_one();
if(!packet)
{
if(!ret) return AVErrorEOF;
std::cerr<< "Failed to send flush packet: "<<ret <<std::endl;
return ret;
}
if(ret < 0)
std::cerr<< "Failed to send packet: "<<ret <<std::endl;
return ret;
}
int receiveFrame(AVCodecContext *codecctx, AVFrame *frame)
{
int ret{};
{
std::unique_lock<std::mutex> flock{mFrameMutex};
while((ret=avcodec_receive_frame(codecctx, frame)) == AVERROR(EAGAIN))
mOutFrameCond.wait_for(flock, milliseconds{50});
}
mInFrameCond.notify_one();
return ret;
}
void setFinished()
{
{
std::lock_guard<std::mutex> _{mPacketMutex};
mFinished = true;
}
mPacketCond.notify_one();
}
void flush()
{
{
std::lock_guard<std::mutex> _{mPacketMutex};
mFinished = true;
mPackets.clear();
mTotalSize = 0;
}
mPacketCond.notify_one();
}
bool put(const AVPacket *pkt)
{
{
std::unique_lock<std::mutex> lock{mPacketMutex};
if(mTotalSize >= SizeLimit || mFinished)
return false;
mPackets.push_back(AVPacketPtr{av_packet_alloc()});
if(av_packet_ref(mPackets.back().get(), pkt) != 0)
{
mPackets.pop_back();
return true;
}
mTotalSize += static_cast<unsigned int>(mPackets.back()->size);
}
mPacketCond.notify_one();
return true;
}
};