Add guard to handle resetting AVPacket after use.
Also handle allocation failures.pull/4202/head
parent
4020be4ea8
commit
e4b45b89d5
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue