Add guard to handle resetting AVPacket after use.

Also handle allocation failures.
pull/4202/head
Doug Nazar 2022-07-28 00:37:02 -04:00 committed by Isaac Connor
parent 4020be4ea8
commit e4b45b89d5
7 changed files with 65 additions and 26 deletions

View File

@ -513,4 +513,38 @@ struct zm_free_av_packet
using av_packet_ptr = std::unique_ptr<AVPacket, zm_free_av_packet>;
struct av_packet_guard
{
av_packet_guard() : packet{nullptr}
{
}
explicit av_packet_guard(const av_packet_ptr& p) : packet{p.get()}
{
}
explicit av_packet_guard(AVPacket *p) : packet{p}
{
}
~av_packet_guard()
{
if (packet)
av_packet_unref(packet);
}
void acquire(const av_packet_ptr& p)
{
packet = p.get();
}
void acquire(AVPacket *p)
{
packet = p;
}
void release()
{
packet = nullptr;
}
private:
AVPacket *packet;
};
#endif // ZM_FFMPEG_H

View File

@ -235,6 +235,8 @@ int FfmpegCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
return -1;
}
av_packet_guard pkt_guard{packet};
AVStream *stream = formatContextPtr->streams[packet->stream_index];
ZM_DUMP_STREAM_PACKET(stream, packet, "ffmpeg_camera in");
@ -260,7 +262,6 @@ int FfmpegCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
mLastAudioPTS = packet->pts - mFirstAudioPTS;
}
}
zm_av_packet_unref(packet.get());
return 1;
} // FfmpegCamera::Capture

View File

@ -168,6 +168,11 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
int frameComplete = false;
av_packet_ptr packet{av_packet_alloc()};
if (!packet) {
Error("Unable to allocate packet.");
return nullptr;
}
while (!frameComplete) {
int ret = av_read_frame(input_format_context, packet.get());
if (ret < 0) {
@ -186,9 +191,9 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
}
ZM_DUMP_STREAM_PACKET(input_format_context->streams[packet->stream_index], packet, "Received packet");
av_packet_guard pkt_guard{packet};
if ((stream_id >= 0) && (packet->stream_index != stream_id)) {
Debug(1,"Packet is not for our stream (%d)", packet->stream_index );
zm_av_packet_unref(packet.get());
continue;
}
@ -204,7 +209,6 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
if ( ret < 0 ) {
Error("Unable to decode frame at frame %d: %d %s, continuing",
streams[packet->stream_index].frame_count, ret, av_make_error_string(ret).c_str());
zm_av_packet_unref(packet.get());
av_frame_free(&frame);
continue;
} else {
@ -239,7 +243,6 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
zm_dump_frame(frame, "resulting frame");
}
zm_av_packet_unref(packet.get());
} // end while !frameComplete
return frame;
} // end AVFrame *FFmpeg_Input::get_frame

View File

@ -94,6 +94,11 @@ AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
AVFrame *frame = zm_av_frame_alloc();
char errbuf[AV_ERROR_MAX_STRING_SIZE];
if (!packet) {
Error("Unable to allocate packet.");
return nullptr;
}
while ( !frameComplete ) {
int ret = av_read_frame( input_format_context, packet.get() );
if ( ret < 0 ) {
@ -111,6 +116,8 @@ AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
return NULL;
}
av_packet_guard pkt_guard{packet};
if ( (stream_id < 0 ) || ( packet->stream_index == stream_id ) ) {
Debug(1,"Packet is for our stream (%d)", packet->stream_index );
@ -121,7 +128,6 @@ AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
zm_av_packet_unref( packet.get() );
continue;
} else {
Debug(1, "Success getting a packet");
@ -133,14 +139,12 @@ AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to receive frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
zm_av_packet_unref( packet.get() );
continue;
}
ret = av_hwframe_transfer_data(frame, hwFrame, 0);
if (ret < 0) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
zm_av_packet_unref( packet.get() );
continue;
}
} else {
@ -150,7 +154,6 @@ AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet->stream_index].frame_count, errbuf );
zm_av_packet_unref( packet.get() );
continue;
}
@ -170,8 +173,6 @@ AVFrame *FFmpeg_Output::get_frame( int stream_id ) {
#endif
} // end if it's the right stream
zm_av_packet_unref( packet.get() );
} // end while ! frameComplete
return frame;

View File

@ -95,14 +95,6 @@ ZMPacket::~ZMPacket() {
delete image;
}
ssize_t ZMPacket::ram() {
return packet->size +
(in_frame ? in_frame->linesize[0] * in_frame->height : 0) +
(out_frame ? out_frame->linesize[0] * out_frame->height : 0) +
(image ? image->Size() : 0) +
(analysis_image ? analysis_image->Size() : 0);
}
/* returns < 0 on error, 0 on not ready, int bytes consumed on success
* This functions job is to populate in_frame with the image in an appropriate
* format. It MAY also populate image if able to. In this case in_frame is populated

View File

@ -90,14 +90,14 @@ bool PacketQueue::queuePacket(std::shared_ptr<ZMPacket> add_packet) {
std::unique_lock<std::mutex> lck(mutex);
if (deleting or zm_terminate) return false;
if (!has_out_of_order_packets_ and (add_packet->packet.dts != AV_NOPTS_VALUE)) {
if (!has_out_of_order_packets_ and (add_packet->packet->dts != AV_NOPTS_VALUE)) {
auto rit = pktQueue.rbegin();
// Find the previous packet for the stream, and check dts
while (rit != pktQueue.rend()) {
std::shared_ptr<ZMPacket> prev_packet = *rit;
if (prev_packet->packet.stream_index == add_packet->packet.stream_index) {
if (prev_packet->packet.dts >= add_packet->packet.dts) {
if (prev_packet->packet->stream_index == add_packet->packet->stream_index) {
if (prev_packet->packet->dts >= add_packet->packet->dts) {
Debug(1, "Have out of order packets");
ZM_DUMP_PACKET(prev_packet->packet, "queued_packet");
ZM_DUMP_PACKET(add_packet->packet, "add_packet");

View File

@ -560,6 +560,11 @@ void VideoStore::flush_codecs() {
// whatever we get. Failures are not fatal.
av_packet_ptr pkt{av_packet_alloc()};
if (!pkt) {
Error("Unable to allocate packet.");
return;
}
// I got crashes if the codec didn't do DELAY, so let's test for it.
if (video_out_ctx->codec && ( video_out_ctx->codec->capabilities &
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
@ -570,11 +575,11 @@ void VideoStore::flush_codecs() {
)) {
// Put encoder into flushing mode
while ((zm_send_frame_receive_packet(video_out_ctx, nullptr, *pkt)) > 0) {
av_packet_guard pkt_guard{pkt};
av_packet_rescale_ts(pkt.get(),
video_out_ctx->time_base,
video_out_stream->time_base);
write_packet(pkt.get(), video_out_stream);
zm_av_packet_unref(pkt.get());
} // while have buffered frames
Debug(1, "Done writing buffered video.");
} // end if have delay capability
@ -594,11 +599,11 @@ void VideoStore::flush_codecs() {
// Should probably set the frame size to what is reported FIXME
if (zm_get_samples_from_fifo(fifo, out_frame)) {
if (zm_send_frame_receive_packet(audio_out_ctx, out_frame, *pkt) > 0) {
av_packet_guard pkt_guard{pkt};
av_packet_rescale_ts(pkt.get(),
audio_out_ctx->time_base,
audio_out_stream->time_base);
write_packet(pkt.get(), audio_out_stream);
zm_av_packet_unref(pkt.get());
}
} // end if data returned from fifo
}
@ -615,13 +620,13 @@ void VideoStore::flush_codecs() {
// SHould probably set the frame size to what is reported FIXME
if (av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size)) {
if (zm_send_frame_receive_packet(audio_out_ctx, out_frame, *pkt)) {
av_packet_guard pkt_guard{pkt};
pkt->stream_index = audio_out_stream->index;
av_packet_rescale_ts(pkt.get(),
audio_out_ctx->time_base,
audio_out_stream->time_base);
write_packet(pkt.get(), audio_out_stream);
zm_av_packet_unref(pkt.get());
}
} // end if data returned from fifo
} // end while still data in the fifo
@ -636,12 +641,12 @@ void VideoStore::flush_codecs() {
Debug(1, "No more packets");
break;
}
av_packet_guard pkt_guard{pkt};
ZM_DUMP_PACKET(pkt, "raw from encoder");
av_packet_rescale_ts(pkt.get(), audio_out_ctx->time_base, audio_out_stream->time_base);
ZM_DUMP_STREAM_PACKET(audio_out_stream, pkt, "writing flushed packet");
write_packet(pkt.get(), audio_out_stream);
zm_av_packet_unref(pkt.get());
} // while have buffered frames
} // end if audio_out_codec
} // end flush_codecs
@ -1150,6 +1155,8 @@ int VideoStore::writePacket(const std::shared_ptr<ZMPacket> zm_pkt) {
}
int VideoStore::writeVideoFramePacket(const std::shared_ptr<ZMPacket> zm_packet) {
av_packet_guard pkt_guard;
frame_count += 1;
// if we have to transcode
@ -1271,6 +1278,7 @@ int VideoStore::writeVideoFramePacket(const std::shared_ptr<ZMPacket> zm_packet)
}
return ret;
}
pkt_guard.acquire(opkt);
ZM_DUMP_PACKET(opkt, "packet returned by codec");
// Need to adjust pts/dts values from codec time to stream time
@ -1327,6 +1335,7 @@ int VideoStore::writeVideoFramePacket(const std::shared_ptr<ZMPacket> zm_packet)
ZM_DUMP_STREAM_PACKET(video_in_stream, ipkt, "Doing passthrough, just copy packet");
// Just copy it because the codec is the same
av_packet_ref(opkt.get(), ipkt);
pkt_guard.acquire(opkt);
if (ipkt->dts != AV_NOPTS_VALUE) {
if (video_first_dts == AV_NOPTS_VALUE) {
@ -1345,7 +1354,6 @@ int VideoStore::writeVideoFramePacket(const std::shared_ptr<ZMPacket> zm_packet)
} // end if codec matches
write_packet(opkt.get(), video_out_stream);
zm_av_packet_unref(opkt.get());
if (hw_frame) av_frame_free(&hw_frame);
return 1;