This commit is contained in:
Isaac Connor 2019-02-15 17:52:51 -05:00
commit 9656032906
2 changed files with 87 additions and 44 deletions

View File

@ -210,6 +210,9 @@ VideoStore::VideoStore(
out_frame = NULL; out_frame = NULL;
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE) #if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
resample_ctx = NULL; resample_ctx = NULL;
#if defined(HAVE_LIBSWRESAMPLE)
fifo = NULL;
#endif
#endif #endif
if ( audio_in_stream ) { if ( audio_in_stream ) {
@ -471,6 +474,10 @@ VideoStore::~VideoStore() {
#if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE) #if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE)
if ( resample_ctx ) { if ( resample_ctx ) {
#if defined(HAVE_LIBSWRESAMPLE) #if defined(HAVE_LIBSWRESAMPLE)
if ( fifo ) {
av_audio_fifo_free(fifo);
fifo = NULL;
}
swr_free(&resample_ctx); swr_free(&resample_ctx);
#else #else
#if defined(HAVE_LIBAVRESAMPLE) #if defined(HAVE_LIBAVRESAMPLE)
@ -569,7 +576,7 @@ bool VideoStore::setup_resampler() {
if ( audio_out_codec->supported_samplerates ) { if ( audio_out_codec->supported_samplerates ) {
int found = 0; int found = 0;
for ( unsigned int i = 0; audio_out_codec->supported_samplerates[i]; i++) { for ( unsigned int i = 0; audio_out_codec->supported_samplerates[i]; i++ ) {
if ( audio_out_ctx->sample_rate == if ( audio_out_ctx->sample_rate ==
audio_out_codec->supported_samplerates[i] ) { audio_out_codec->supported_samplerates[i] ) {
found = 1; found = 1;
@ -602,7 +609,7 @@ bool VideoStore::setup_resampler() {
ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts); ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts);
av_dict_free(&opts); av_dict_free(&opts);
if ( ret < 0 ) { if ( ret < 0 ) {
Error("could not open codec (%d) (%s)\n", ret, av_make_error_string(ret).c_str()); Error("could not open codec (%d) (%s)", ret, av_make_error_string(ret).c_str());
audio_out_codec = NULL; audio_out_codec = NULL;
audio_out_ctx = NULL; audio_out_ctx = NULL;
audio_out_stream = NULL; audio_out_stream = NULL;
@ -618,6 +625,12 @@ bool VideoStore::setup_resampler() {
} }
#endif #endif
Debug(1,
"Audio in bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) "
"layout(%d) frame_size(%d)",
audio_in_ctx->bit_rate, audio_in_ctx->sample_rate,
audio_in_ctx->channels, audio_in_ctx->sample_fmt,
audio_in_ctx->channel_layout, audio_in_ctx->frame_size);
Debug(1, Debug(1,
"Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) "
"layout(%d) frame_size(%d)", "layout(%d) frame_size(%d)",
@ -639,6 +652,12 @@ bool VideoStore::setup_resampler() {
} }
#if defined(HAVE_LIBSWRESAMPLE) #if defined(HAVE_LIBSWRESAMPLE)
if (!(fifo = av_audio_fifo_alloc(
audio_out_ctx->sample_fmt,
audio_out_ctx->channels, 1))) {
Error("Could not allocate FIFO");
return false;
}
resample_ctx = swr_alloc_set_opts(NULL, resample_ctx = swr_alloc_set_opts(NULL,
audio_out_ctx->channel_layout, audio_out_ctx->channel_layout,
audio_out_ctx->sample_fmt, audio_out_ctx->sample_fmt,
@ -725,7 +744,7 @@ bool VideoStore::setup_resampler() {
out_frame, audio_out_ctx->channels, out_frame, audio_out_ctx->channels,
audio_out_ctx->sample_fmt, audio_out_ctx->sample_fmt,
(const uint8_t *)converted_in_samples, (const uint8_t *)converted_in_samples,
audioSampleBuffer_size, 0) < 0) { audioSampleBuffer_size, 0) < 0 ) {
Error("Could not allocate converted in sample pointers"); Error("Could not allocate converted in sample pointers");
return false; return false;
} }
@ -749,10 +768,8 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
av_rescale_q(ipkt->pts - video_last_pts, video_in_stream->time_base, av_rescale_q(ipkt->pts - video_last_pts, video_in_stream->time_base,
video_out_stream->time_base); video_out_stream->time_base);
Debug(1, "duration calc: pts(%" PRId64 ") - last_pts(% " PRId64 ") = (%" PRId64 ")", Debug(1, "duration calc: pts(%" PRId64 ") - last_pts(% " PRId64 ") = (%" PRId64 ")",
ipkt->pts, ipkt->pts, video_last_pts, duration);
video_last_pts, if ( duration <= 0 ) {
duration);
if (duration <= 0) {
duration = ipkt->duration ? ipkt->duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base); duration = ipkt->duration ? ipkt->duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base);
} }
} }
@ -824,7 +841,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
} }
} }
#endif #endif
if (opkt.dts > opkt.pts) { if ( opkt.dts > opkt.pts ) {
Debug(1, Debug(1,
"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen "
"before presentation.", "before presentation.",
@ -834,22 +851,20 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
opkt.flags = ipkt->flags; opkt.flags = ipkt->flags;
opkt.pos = -1; opkt.pos = -1;
opkt.data = ipkt->data; opkt.data = ipkt->data;
opkt.size = ipkt->size; opkt.size = ipkt->size;
opkt.stream_index = video_out_stream->index; opkt.stream_index = video_out_stream->index;
AVPacket safepkt; AVPacket safepkt;
memcpy(&safepkt, &opkt, sizeof(AVPacket)); memcpy(&safepkt, &opkt, sizeof(AVPacket));
dumpPacket( &opkt, "writing video packet" ); dumpPacket(&opkt, "writing video packet");
if ((opkt.data == NULL) || (opkt.size < 1)) { if ( (opkt.data == NULL) || (opkt.size < 1) ) {
Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__); Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__);
dumpPacket(ipkt); dumpPacket(ipkt);
dumpPacket(&opkt); dumpPacket(&opkt);
} else if ((video_next_dts > 0) && (video_next_dts > opkt.dts)) { } else if ( (video_next_dts > 0) && (video_next_dts > opkt.dts) ) {
Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame",
__FILE__, __LINE__, video_next_dts, opkt.dts); __FILE__, __LINE__, video_next_dts, opkt.dts);
video_next_dts = opkt.dts; video_next_dts = opkt.dts;
@ -859,12 +874,11 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
video_next_dts = opkt.dts + duration; video_next_dts = opkt.dts + duration;
video_next_pts = opkt.pts + duration; video_next_pts = opkt.pts + duration;
ret = av_interleaved_write_frame(oc, &opkt); ret = av_interleaved_write_frame(oc, &opkt);
if (ret < 0) { if ( ret < 0 ) {
// There's nothing we can really do if the frame is rejected, just drop it // There's nothing we can really do if the frame is rejected, just drop it
// and get on with the next // and get on with the next
Warning( Warning(
"%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) " "%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d)"
" ",
__FILE__, __LINE__, av_make_error_string(ret).c_str(), ret); __FILE__, __LINE__, av_make_error_string(ret).c_str(), ret);
dumpPacket(&safepkt); dumpPacket(&safepkt);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
@ -932,36 +946,63 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
return 0; return 0;
} }
#endif #endif
int frame_size = in_frame->nb_samples;
// Resample the in into the audioSampleBuffer until we proceed the whole // Resample the in into the audioSampleBuffer until we proceed the whole
// decoded data // decoded data
zm_dump_frame(in_frame, "In frame"); Debug(2, "Converting %d to %d samples", in_frame->nb_samples, out_frame->nb_samples);
zm_dump_frame(out_frame, "Out frame before resample");
#if defined(HAVE_LIBSWRESAMPLE) #if defined(HAVE_LIBSWRESAMPLE)
#if 0 #if 0
(ret = swr_convert(resample_ctx, ret = swr_convert(resample_ctx,
out_frame->data, frame_size, out_frame->data, frame_size,
(const uint8_t**)in_frame->data, (const uint8_t**)in_frame->data,
in_frame->nb_samples in_frame->nb_samples
)) );
#else #else
ret = swr_convert_frame(resample_ctx, out_frame, in_frame); ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
#endif
#else
#if defined(HAVE_LIBAVRESAMPLE)
ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data,
0, in_frame->nb_samples);
#endif
#endif
out_frame->pts = in_frame->pts;
av_frame_unref(in_frame); av_frame_unref(in_frame);
if ( ret < 0 ) { if ( ret < 0 ) {
Error("Could not resample frame (error '%s')", Error("Could not resample frame (error '%s')",
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
return 0; return 0;
} }
#endif
if ((ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples)) < 0) {
Error("Could not reallocate FIFO");
return 0;
}
/** Store the new samples in the FIFO buffer. */
ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples);
if ( ret < frame_size ) {
Error("Could not write data to FIFO on %d written", ret);
return 0;
}
#if defined(HAVE_LIBAVRESAMPLE) // Reset frame_size to output_frame_size
frame_size = audio_out_ctx->frame_size;
// AAC requires 1024 samples per encode. Our input tends to be 160, so need to buffer them.
if ( frame_size > av_audio_fifo_size(fifo) ) {
return 0;
}
if ( av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size) < frame_size ) {
Error("Could not read data from FIFO");
return 0;
}
out_frame->nb_samples = frame_size;
/// FIXME this is not the correct pts
out_frame->pts = in_frame->pts;
#else
#if defined(HAVE_LIBAVRESAMPLE)
(ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data,
0, in_frame->nb_samples))
av_frame_unref(in_frame);
if ( ret < 0 ) {
Error("Could not resample frame (error '%s')",
av_make_error_string(ret).c_str());
return 0;
}
int samples_available = avresample_available(resample_ctx); int samples_available = avresample_available(resample_ctx);
if ( samples_available < frame_size ) { if ( samples_available < frame_size ) {
@ -975,11 +1016,11 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
Warning("Error reading resampled audio:"); Warning("Error reading resampled audio:");
return 0; return 0;
} }
#endif
#endif #endif
zm_dump_frame(out_frame,"Out frame after resample"); zm_dump_frame(out_frame, "Out frame after resample");
av_init_packet(&opkt); av_init_packet(&opkt);
Debug(5, "after init packet");
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ( (ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0 ) { if ( (ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0 ) {
@ -993,7 +1034,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
if ( (ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0 ) { if ( (ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0 ) {
if ( AVERROR(EAGAIN) == ret ) { if ( AVERROR(EAGAIN) == ret ) {
// THe codec may need more samples than it has, perfectly valid // The codec may need more samples than it has, perfectly valid
Debug(3, "Could not recieve packet (error '%s')", Debug(3, "Could not recieve packet (error '%s')",
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
} else { } else {
@ -1083,7 +1124,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
} }
#endif #endif
// audio_last_dts = ipkt->dts; // audio_last_dts = ipkt->dts;
if (opkt.dts > opkt.pts) { if ( opkt.dts > opkt.pts ) {
Debug(1, Debug(1,
"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen "
"before presentation.", "before presentation.",
@ -1093,16 +1134,16 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
// I wonder if we could just use duration instead of all the hoop jumping // I wonder if we could just use duration instead of all the hoop jumping
// above? // above?
//
if (out_frame) { if ( out_frame ) {
opkt.duration = out_frame->nb_samples; opkt.duration = out_frame->nb_samples;
} else { } else {
opkt.duration = ipkt->duration; opkt.duration = ipkt->duration;
} }
// opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base,
// audio_out_stream->time_base); // audio_out_stream->time_base);
Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)",
opkt.dts, opkt.duration); opkt.pts, opkt.dts, opkt.duration);
// pkt.pos: byte position in stream, -1 if unknown // pkt.pos: byte position in stream, -1 if unknown
opkt.pos = -1; opkt.pos = -1;
@ -1113,8 +1154,8 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
AVPacket safepkt; AVPacket safepkt;
memcpy(&safepkt, &opkt, sizeof(AVPacket)); memcpy(&safepkt, &opkt, sizeof(AVPacket));
ret = av_interleaved_write_frame(oc, &opkt); ret = av_interleaved_write_frame(oc, &opkt);
if (ret != 0) { if ( ret != 0 ) {
Error("Error writing audio frame packet: %s\n", Error("Error writing audio frame packet: %s",
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
dumpPacket(&safepkt); dumpPacket(&safepkt);
} else { } else {
@ -1122,4 +1163,4 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
} }
zm_av_packet_unref(&opkt); zm_av_packet_unref(&opkt);
return 0; return 0;
} // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) } // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)

View File

@ -5,6 +5,7 @@
extern "C" { extern "C" {
#ifdef HAVE_LIBSWRESAMPLE #ifdef HAVE_LIBSWRESAMPLE
#include "libswresample/swresample.h" #include "libswresample/swresample.h"
#include "libavutil/audio_fifo.h"
#else #else
#ifdef HAVE_LIBAVRESAMPLE #ifdef HAVE_LIBAVRESAMPLE
#include "libavresample/avresample.h" #include "libavresample/avresample.h"
@ -44,6 +45,7 @@ private:
AVCodecContext *audio_out_ctx; AVCodecContext *audio_out_ctx;
#ifdef HAVE_LIBSWRESAMPLE #ifdef HAVE_LIBSWRESAMPLE
SwrContext *resample_ctx; SwrContext *resample_ctx;
AVAudioFifo *fifo;
#else #else
#ifdef HAVE_LIBAVRESAMPLE #ifdef HAVE_LIBAVRESAMPLE
AVAudioResampleContext* resample_ctx; AVAudioResampleContext* resample_ctx;