add flushing the resample buffer to get the remaining samples encoded
parent
16a7ab1392
commit
701aa8d924
|
@ -505,7 +505,10 @@ int zm_receive_packet(AVCodecContext *context, AVPacket &packet) {
|
|||
#endif
|
||||
} // end int zm_receive_packet(AVCodecContext *context, AVPacket &packet)
|
||||
|
||||
int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet) {
|
||||
int zm_send_packet_receive_frame(
|
||||
AVCodecContext *context,
|
||||
AVFrame *frame,
|
||||
AVPacket &packet) {
|
||||
int ret;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
if ( (ret = avcodec_send_packet(context, &packet)) < 0 ) {
|
||||
|
@ -533,29 +536,31 @@ int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
|||
}
|
||||
} // end while !frameComplete
|
||||
#endif
|
||||
return 0;
|
||||
} // end int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
||||
return 1;
|
||||
} // end int zm_send_packet_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
||||
|
||||
int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
||||
/* Returns < 0 on error, 0 if codec not ready, 1 on success
|
||||
*/
|
||||
int zm_send_frame_receive_packet(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
||||
int ret;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
if ( (ret = avcodec_send_frame(ctx, frame)) < 0 ) {
|
||||
Error("Could not send frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
zm_av_packet_unref(&packet);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ( (ret = avcodec_receive_packet(ctx, &packet)) < 0 ) {
|
||||
if ( AVERROR(EAGAIN) == ret ) {
|
||||
// The codec may need more samples than it has, perfectly valid
|
||||
Debug(2, "Codec not ready to give us a packet");
|
||||
return 0;
|
||||
} else {
|
||||
Error("Could not recieve packet (error %d = '%s')", ret,
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
zm_av_packet_unref(&packet);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
int data_present;
|
||||
|
@ -564,7 +569,7 @@ int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
|||
Error("Could not encode frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
zm_av_packet_unref(&packet);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
if ( !data_present ) {
|
||||
Debug(2, "Not ready to out a frame yet.");
|
||||
|
@ -573,7 +578,7 @@ int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
|||
}
|
||||
#endif
|
||||
return 1;
|
||||
} // wend zm_send_frame
|
||||
} // end int zm_send_frame_receive_packet
|
||||
|
||||
void dumpPacket(AVStream *stream, AVPacket *pkt, const char *text) {
|
||||
char b[10240];
|
||||
|
|
|
@ -354,8 +354,8 @@ bool is_audio_context(AVCodec *);
|
|||
|
||||
int zm_receive_packet(AVCodecContext *context, AVPacket &packet);
|
||||
|
||||
int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
|
||||
int zm_send_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
|
||||
int zm_send_packet_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
|
||||
int zm_send_frame_receive_packet(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
|
||||
|
||||
void dumpPacket(AVStream *, AVPacket *,const char *text="");
|
||||
void dumpPacket(AVPacket *,const char *text="");
|
||||
|
|
|
@ -260,8 +260,8 @@ int FfmpegCamera::Capture(Image &image) {
|
|||
&&
|
||||
(keyframe || have_video_keyframe)
|
||||
) {
|
||||
ret = zm_receive_frame(mVideoCodecContext, mRawFrame, packet);
|
||||
if ( ret < 0 ) {
|
||||
ret = zm_send_packet_receive_frame(mVideoCodecContext, mRawFrame, packet);
|
||||
if ( ret <= 0 ) {
|
||||
Error("Unable to get frame at frame %d: %s, continuing",
|
||||
frameCount, av_make_error_string(ret).c_str());
|
||||
zm_av_packet_unref(&packet);
|
||||
|
@ -952,8 +952,8 @@ int FfmpegCamera::CaptureAndRecord(
|
|||
}
|
||||
} // end if keyframe or have_video_keyframe
|
||||
|
||||
ret = zm_receive_frame(mVideoCodecContext, mRawFrame, packet);
|
||||
if ( ret < 0 ) {
|
||||
ret = zm_send_packet_receive_frame(mVideoCodecContext, mRawFrame, packet);
|
||||
if ( ret <= 0 ) {
|
||||
Warning("Unable to receive frame %d: %s. error count is %d",
|
||||
frameCount, av_make_error_string(ret).c_str(), error_count);
|
||||
error_count += 1;
|
||||
|
|
|
@ -137,8 +137,8 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
|
|||
} else {
|
||||
frame = zm_av_frame_alloc();
|
||||
}
|
||||
ret = zm_receive_frame(context, frame, packet);
|
||||
if ( ret < 0 ) {
|
||||
ret = zm_send_packet_receive_frame(context, frame, packet);
|
||||
if ( ret <= 0 ) {
|
||||
Error("Unable to decode frame at frame %d: %s, continuing",
|
||||
streams[packet.stream_index].frame_count, av_make_error_string(ret).c_str());
|
||||
zm_av_packet_unref(&packet);
|
||||
|
|
|
@ -441,11 +441,39 @@ VideoStore::~VideoStore() {
|
|||
pkt.size = 0;
|
||||
av_init_packet(&pkt);
|
||||
|
||||
int frame_size = audio_out_ctx->frame_size;
|
||||
/*
|
||||
* At the end of the file, we pass the remaining samples to
|
||||
* the encoder. */
|
||||
int frame_size = audio_out_ctx->frame_size;
|
||||
Debug(2, "av_audio_fifo_size = %s", av_audio_fifo_size(fifo));
|
||||
while ( swr_get_delay(resample_ctx, audio_out_ctx->sample_rate) ) {
|
||||
swr_convert_frame(resample_ctx, out_frame, NULL);
|
||||
int ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not reallocate FIFO to %d samples",
|
||||
av_audio_fifo_size(fifo) + out_frame->nb_samples);
|
||||
} else {
|
||||
/** Store the new samples in the FIFO buffer. */
|
||||
ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples);
|
||||
if ( ret < out_frame->nb_samples ) {
|
||||
Error("Could not write data to FIFO. %d written, expecting %d. Reason %s",
|
||||
ret, out_frame->nb_samples, av_make_error_string(ret).c_str());
|
||||
}
|
||||
// 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) ) {
|
||||
pkt.stream_index = audio_out_stream->index;
|
||||
|
||||
av_packet_rescale_ts(&pkt,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
write_packet(&pkt, audio_out_stream);
|
||||
}
|
||||
} // end if data returned from fifo
|
||||
}
|
||||
|
||||
} // end if have buffered samples in the resampler
|
||||
|
||||
Debug(2, "av_audio_fifo_size = %d", av_audio_fifo_size(fifo));
|
||||
while ( av_audio_fifo_size(fifo) > 0 ) {
|
||||
/* Take one frame worth of audio samples from the FIFO buffer,
|
||||
* encode it and write it to the output file. */
|
||||
|
@ -455,13 +483,13 @@ VideoStore::~VideoStore() {
|
|||
|
||||
// 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(audio_out_ctx, out_frame, pkt) ) {
|
||||
if ( zm_send_frame_receive_packet(audio_out_ctx, out_frame, pkt) ) {
|
||||
pkt.stream_index = audio_out_stream->index;
|
||||
|
||||
pkt.duration = av_rescale_q(
|
||||
pkt.duration,
|
||||
av_packet_rescale_ts(&pkt,
|
||||
audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
write_packet(&pkt, audio_out_stream);
|
||||
}
|
||||
} // end if data returned from fifo
|
||||
} // end while still data in the fifo
|
||||
|
@ -472,15 +500,15 @@ VideoStore::~VideoStore() {
|
|||
#endif
|
||||
|
||||
while (1) {
|
||||
if ( ! zm_receive_packet(audio_out_ctx, pkt) )
|
||||
if ( ! zm_receive_packet(audio_out_ctx, pkt) ) {
|
||||
Debug(1, "No more packets");
|
||||
break;
|
||||
}
|
||||
|
||||
dumpPacket(&pkt, "raw from encoder");
|
||||
pkt.stream_index = audio_out_stream->index;
|
||||
|
||||
av_packet_rescale_ts(&pkt, audio_out_ctx->time_base, audio_out_stream->time_base);
|
||||
dumpPacket(audio_out_stream, &pkt, "writing flushed packet");
|
||||
av_interleaved_write_frame(oc, &pkt);
|
||||
write_packet(&pkt, audio_out_stream);
|
||||
zm_av_packet_unref(&pkt);
|
||||
} // while have buffered frames
|
||||
} // end if audio_out_codec
|
||||
|
@ -858,108 +886,36 @@ bool VideoStore::setup_resampler() {
|
|||
int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
||||
av_init_packet(&opkt);
|
||||
|
||||
dumpPacket(video_in_stream, ipkt, "input packet");
|
||||
dumpPacket(video_in_stream, ipkt, "video input packet");
|
||||
|
||||
int64_t duration;
|
||||
if ( ipkt->duration != AV_NOPTS_VALUE ) {
|
||||
duration = av_rescale_q(
|
||||
ipkt->duration,
|
||||
video_in_stream->time_base,
|
||||
video_out_stream->time_base);
|
||||
Debug(1, "duration from ipkt: %" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)",
|
||||
ipkt->duration,
|
||||
duration,
|
||||
video_in_stream->time_base.num,
|
||||
video_in_stream->time_base.den,
|
||||
video_out_stream->time_base.num,
|
||||
video_out_stream->time_base.den
|
||||
);
|
||||
} else {
|
||||
duration = av_rescale_q(
|
||||
ipkt->pts - video_last_pts,
|
||||
video_in_stream->time_base,
|
||||
video_out_stream->time_base);
|
||||
Debug(1, "duration calc: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ")",
|
||||
ipkt->pts,
|
||||
video_last_pts,
|
||||
ipkt->pts - video_last_pts,
|
||||
duration
|
||||
);
|
||||
if ( duration <= 0 ) {
|
||||
// Why are we setting the duration to 1?
|
||||
Warning("Duration is 0, setting to 1");
|
||||
duration = ipkt->duration ? ipkt->duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base);
|
||||
}
|
||||
}
|
||||
opkt.duration = duration;
|
||||
opkt.flags = ipkt->flags;
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
opkt.duration = ipkt->duration;
|
||||
|
||||
// Scale the PTS of the outgoing packet to be the correct time base
|
||||
if ( ipkt->pts != AV_NOPTS_VALUE ) {
|
||||
|
||||
if ( (!video_first_pts) && (ipkt->pts >= 0) ) {
|
||||
// This is the first packet.
|
||||
opkt.pts = 0;
|
||||
Debug(2, "Starting video first_pts will become %" PRId64, ipkt->pts);
|
||||
video_first_pts = ipkt->pts;
|
||||
} else {
|
||||
opkt.pts = av_rescale_q(
|
||||
ipkt->pts - video_first_pts,
|
||||
video_in_stream->time_base,
|
||||
video_out_stream->time_base
|
||||
);
|
||||
}
|
||||
Debug(3, "opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")",
|
||||
opkt.pts, ipkt->pts, video_first_pts);
|
||||
video_last_pts = ipkt->pts;
|
||||
} else {
|
||||
Debug(3, "opkt.pts = undef");
|
||||
opkt.pts = AV_NOPTS_VALUE;
|
||||
opkt.pts = ipkt->pts - video_first_pts;
|
||||
}
|
||||
// Just because the in stream wraps, doesn't mean the out needs to.
|
||||
// Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out.
|
||||
// So need to handle in wrap, without causing out wrap.
|
||||
// The cameras that Icon has seem to do EOF instead of wrapping
|
||||
|
||||
if ( ipkt->dts != AV_NOPTS_VALUE ) {
|
||||
if ( !video_first_dts ) {
|
||||
// && ( ipkt->dts >= 0 ) ) {
|
||||
// This is the first packet.
|
||||
opkt.dts = 0;
|
||||
Debug(2, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
|
||||
Debug(2, "Starting video first_dts will become %" PRId64, ipkt->dts);
|
||||
video_first_dts = ipkt->dts;
|
||||
} else {
|
||||
opkt.dts = av_rescale_q(
|
||||
ipkt->dts - video_first_dts,
|
||||
video_in_stream->time_base,
|
||||
video_out_stream->time_base
|
||||
);
|
||||
Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")",
|
||||
opkt.dts, ipkt->dts, video_first_dts);
|
||||
}
|
||||
if ( (opkt.pts != AV_NOPTS_VALUE) && (opkt.dts > opkt.pts) ) {
|
||||
Debug(1,
|
||||
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen "
|
||||
"before presentation.",
|
||||
opkt.dts, opkt.pts);
|
||||
opkt.dts = opkt.pts;
|
||||
}
|
||||
} else {
|
||||
Debug(3, "opkt.dts = undef");
|
||||
opkt.dts = video_out_stream->cur_dts;
|
||||
opkt.dts = ipkt->dts - video_first_dts;
|
||||
}
|
||||
av_packet_rescale_ts(&opkt, video_in_stream->time_base, video_out_stream->time_base);
|
||||
|
||||
if ( opkt.dts < video_out_stream->cur_dts ) {
|
||||
Debug(1, "Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
|
||||
opkt.dts, opkt.pts, video_out_stream->cur_dts);
|
||||
opkt.dts = video_out_stream->cur_dts;
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
opkt.pts = opkt.dts;
|
||||
}
|
||||
}
|
||||
|
||||
opkt.flags = ipkt->flags;
|
||||
opkt.pos = -1;
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
dumpPacket(video_out_stream, &opkt, "after pts adjustment");
|
||||
write_packet(&opkt, video_out_stream);
|
||||
zm_av_packet_unref(&opkt);
|
||||
|
||||
|
@ -1020,7 +976,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
dumpPacket(audio_in_stream, ipkt, "after pts adjustment");
|
||||
|
||||
if ( audio_out_codec ) {
|
||||
if ( ( ret = zm_receive_frame(audio_in_ctx, in_frame, *ipkt) ) < 0 ) {
|
||||
if ( ( ret = zm_send_packet_receive_frame(audio_in_ctx, in_frame, *ipkt) ) <= 0 ) {
|
||||
Debug(3, "Not ready to receive frame");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1034,7 +990,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
zm_dump_frame(out_frame, "Out frame after resample");
|
||||
|
||||
av_init_packet(&opkt);
|
||||
if ( !zm_send_frame(audio_out_ctx, out_frame, opkt) ) {
|
||||
if ( zm_send_frame_receive_packet(audio_out_ctx, out_frame, opkt) <= 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1048,9 +1004,9 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// While the encoder still has packets for us
|
||||
while ( !avcodec_receive_packet(audio_out_ctx, &opkt) ) {
|
||||
while ( ! ( avcodec_receive_packet(audio_out_ctx, &opkt) < 0 ) ) {
|
||||
av_packet_rescale_ts(&opkt, audio_out_ctx->time_base, audio_out_stream->time_base);
|
||||
dumpPacket(audio_out_stream, &opkt, "raw opkt");
|
||||
dumpPacket(audio_out_stream, &opkt, "secondary opkt");
|
||||
write_packet(&opkt, audio_out_stream);
|
||||
}
|
||||
#endif
|
||||
|
@ -1166,12 +1122,15 @@ int VideoStore::resample_audio() {
|
|||
av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
zm_dump_frame(out_frame, "Out frame after resample");
|
||||
out_frame->pkt_duration = in_frame->pkt_duration; // resampling doesn't alter duration
|
||||
zm_dump_frame(out_frame, "Out frame after resample delay");
|
||||
Debug(3,"sws_get_delay %d",
|
||||
swr_get_delay(resample_ctx, audio_out_ctx->sample_rate));
|
||||
//out_frame->pkt_duration = in_frame->pkt_duration; // resampling doesn't alter duration
|
||||
|
||||
ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not reallocate FIFO");
|
||||
Error("Could not reallocate FIFO to %d samples",
|
||||
av_audio_fifo_size(fifo) + out_frame->nb_samples);
|
||||
return 0;
|
||||
}
|
||||
/** Store the new samples in the FIFO buffer. */
|
||||
|
@ -1198,19 +1157,10 @@ int VideoStore::resample_audio() {
|
|||
}
|
||||
out_frame->nb_samples = frame_size;
|
||||
zm_dump_frame(out_frame, "Out frame after fifo read");
|
||||
// resampling changes the duration because the timebase is 1/samples
|
||||
// I think we should be dealing in codec timebases not stream
|
||||
#if 0
|
||||
if ( in_frame->pts != AV_NOPTS_VALUE ) {
|
||||
out_frame->pts = av_rescale_q(
|
||||
in_frame->pts,
|
||||
audio_in_ctx->time_base,
|
||||
audio_out_ctx->time_base);
|
||||
}
|
||||
#else
|
||||
out_frame->pts = audio_next_pts;
|
||||
audio_next_pts += out_frame->nb_samples;
|
||||
#endif
|
||||
|
||||
out_frame->pts = audio_next_pts;
|
||||
audio_next_pts += out_frame->nb_samples;
|
||||
|
||||
zm_dump_frame(out_frame, "Out frame after timestamp conversion");
|
||||
#else
|
||||
#if defined(HAVE_LIBAVRESAMPLE)
|
||||
|
|
Loading…
Reference in New Issue