mirror of https://github.com/procxx/kepka.git
Moved to ffmpeg 3.1 release code.
This commit is contained in:
parent
90b06db479
commit
27cf45e1a9
|
@ -1377,7 +1377,14 @@ void AudioCaptureInner::onStart() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d->stream->id = d->fmtContext->nb_streams - 1;
|
d->stream->id = d->fmtContext->nb_streams - 1;
|
||||||
d->codecContext = d->stream->codec;
|
d->codecContext = avcodec_alloc_context3(d->codec);
|
||||||
|
if (!d->codecContext) {
|
||||||
|
LOG(("Audio Error: Unable to avcodec_alloc_context3 for capture"));
|
||||||
|
onStop(false);
|
||||||
|
emit error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
av_opt_set_int(d->codecContext, "refcounted_frames", 1, 0);
|
av_opt_set_int(d->codecContext, "refcounted_frames", 1, 0);
|
||||||
|
|
||||||
d->codecContext->sample_fmt = AV_SAMPLE_FMT_FLTP;
|
d->codecContext->sample_fmt = AV_SAMPLE_FMT_FLTP;
|
||||||
|
@ -1439,6 +1446,13 @@ void AudioCaptureInner::onStart() {
|
||||||
}
|
}
|
||||||
d->dstSamplesSize = av_samples_get_buffer_size(0, d->codecContext->channels, d->maxDstSamples, d->codecContext->sample_fmt, 0);
|
d->dstSamplesSize = av_samples_get_buffer_size(0, d->codecContext->channels, d->maxDstSamples, d->codecContext->sample_fmt, 0);
|
||||||
|
|
||||||
|
if ((res = avcodec_parameters_from_context(d->stream->codecpar, d->codecContext)) < 0) {
|
||||||
|
LOG(("Audio Error: Unable to avcodec_parameters_from_context for capture, error %1, %2").arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
onStop(false);
|
||||||
|
emit error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Write file header
|
// Write file header
|
||||||
if ((res = avformat_write_header(d->fmtContext, 0)) < 0) {
|
if ((res = avformat_write_header(d->fmtContext, 0)) < 0) {
|
||||||
LOG(("Audio Error: Unable to avformat_write_header for capture, error %1, %2").arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to avformat_write_header for capture, error %1, %2").arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
@ -1486,9 +1500,10 @@ void AudioCaptureInner::onStop(bool needResult) {
|
||||||
|
|
||||||
int32 framesize = d->srcSamples * d->codecContext->channels * sizeof(short), encoded = 0;
|
int32 framesize = d->srcSamples * d->codecContext->channels * sizeof(short), encoded = 0;
|
||||||
while (_captured.size() >= encoded + framesize) {
|
while (_captured.size() >= encoded + framesize) {
|
||||||
writeFrame(encoded, framesize);
|
processFrame(encoded, framesize);
|
||||||
encoded += framesize;
|
encoded += framesize;
|
||||||
}
|
}
|
||||||
|
writeFrame(nullptr); // drain the codec
|
||||||
if (encoded != _captured.size()) {
|
if (encoded != _captured.size()) {
|
||||||
d->fullSamples = 0;
|
d->fullSamples = 0;
|
||||||
d->dataPos = 0;
|
d->dataPos = 0;
|
||||||
|
@ -1545,7 +1560,7 @@ void AudioCaptureInner::onStop(bool needResult) {
|
||||||
d->device = nullptr;
|
d->device = nullptr;
|
||||||
|
|
||||||
if (d->codecContext) {
|
if (d->codecContext) {
|
||||||
avcodec_close(d->codecContext);
|
avcodec_free_context(&d->codecContext);
|
||||||
d->codecContext = nullptr;
|
d->codecContext = nullptr;
|
||||||
}
|
}
|
||||||
if (d->srcSamplesData) {
|
if (d->srcSamplesData) {
|
||||||
|
@ -1648,7 +1663,7 @@ void AudioCaptureInner::onTimeout() {
|
||||||
// Write frames
|
// Write frames
|
||||||
int32 framesize = d->srcSamples * d->codecContext->channels * sizeof(short), encoded = 0;
|
int32 framesize = d->srcSamples * d->codecContext->channels * sizeof(short), encoded = 0;
|
||||||
while (uint32(_captured.size()) >= encoded + framesize + fadeSamples * sizeof(short)) {
|
while (uint32(_captured.size()) >= encoded + framesize + fadeSamples * sizeof(short)) {
|
||||||
writeFrame(encoded, framesize);
|
processFrame(encoded, framesize);
|
||||||
encoded += framesize;
|
encoded += framesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1663,7 +1678,7 @@ void AudioCaptureInner::onTimeout() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) {
|
void AudioCaptureInner::processFrame(int32 offset, int32 framesize) {
|
||||||
// Prepare audio frame
|
// Prepare audio frame
|
||||||
|
|
||||||
if (framesize % sizeof(short)) { // in the middle of a sample
|
if (framesize % sizeof(short)) { // in the middle of a sample
|
||||||
|
@ -1730,33 +1745,93 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) {
|
||||||
|
|
||||||
// Write audio frame
|
// Write audio frame
|
||||||
|
|
||||||
AVPacket pkt;
|
|
||||||
memset(&pkt, 0, sizeof(pkt)); // data and size must be 0;
|
|
||||||
AVFrame *frame = av_frame_alloc();
|
AVFrame *frame = av_frame_alloc();
|
||||||
int gotPacket;
|
|
||||||
av_init_packet(&pkt);
|
|
||||||
|
|
||||||
frame->nb_samples = d->dstSamples;
|
frame->nb_samples = d->dstSamples;
|
||||||
|
frame->pts = av_rescale_q(d->fullSamples, (AVRational){1, d->codecContext->sample_rate}, d->codecContext->time_base);
|
||||||
|
|
||||||
avcodec_fill_audio_frame(frame, d->codecContext->channels, d->codecContext->sample_fmt, d->dstSamplesData[0], d->dstSamplesSize, 0);
|
avcodec_fill_audio_frame(frame, d->codecContext->channels, d->codecContext->sample_fmt, d->dstSamplesData[0], d->dstSamplesSize, 0);
|
||||||
if ((res = avcodec_encode_audio2(d->codecContext, &pkt, frame, &gotPacket)) < 0) {
|
|
||||||
LOG(("Audio Error: Unable to avcodec_encode_audio2 for capture, error %1, %2").arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
writeFrame(frame);
|
||||||
|
|
||||||
|
d->fullSamples += samplesCnt;
|
||||||
|
|
||||||
|
av_frame_free(&frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioCaptureInner::writeFrame(AVFrame *frame) {
|
||||||
|
int res = 0;
|
||||||
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
|
||||||
|
res = avcodec_send_frame(d->codecContext, frame);
|
||||||
|
if (res == AVERROR(EAGAIN)) {
|
||||||
|
int packetsWritten = writePackets();
|
||||||
|
if (packetsWritten < 0) {
|
||||||
|
if (frame && packetsWritten == AVERROR_EOF) {
|
||||||
|
LOG(("Audio Error: EOF in packets received when EAGAIN was got in avcodec_send_frame()"));
|
||||||
|
onStop(false);
|
||||||
|
emit error();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (!packetsWritten) {
|
||||||
|
LOG(("Audio Error: No packets received when EAGAIN was got in avcodec_send_frame()"));
|
||||||
|
onStop(false);
|
||||||
|
emit error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res = avcodec_send_frame(d->codecContext, frame);
|
||||||
|
}
|
||||||
|
if (res < 0) {
|
||||||
|
LOG(("Audio Error: Unable to avcodec_send_frame for capture, error %1, %2").arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
onStop(false);
|
onStop(false);
|
||||||
emit error();
|
emit error();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gotPacket) {
|
if (!frame) { // drain
|
||||||
|
if ((res = writePackets()) != AVERROR_EOF) {
|
||||||
|
LOG(("Audio Error: not EOF in packets received when draining the codec, result %1").arg(res));
|
||||||
|
onStop(false);
|
||||||
|
emit error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioCaptureInner::writePackets() {
|
||||||
|
AVPacket pkt;
|
||||||
|
memset(&pkt, 0, sizeof(pkt)); // data and size must be 0;
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
|
||||||
|
int written = 0;
|
||||||
|
do {
|
||||||
|
av_init_packet(&pkt);
|
||||||
|
if ((res = avcodec_receive_packet(d->codecContext, &pkt)) < 0) {
|
||||||
|
if (res == AVERROR(EAGAIN)) {
|
||||||
|
return written;
|
||||||
|
} else if (res == AVERROR_EOF) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
LOG(("Audio Error: Unable to avcodec_receive_packet for capture, error %1, %2").arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
onStop(false);
|
||||||
|
emit error();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_packet_rescale_ts(&pkt, d->codecContext->time_base, d->stream->time_base);
|
||||||
pkt.stream_index = d->stream->index;
|
pkt.stream_index = d->stream->index;
|
||||||
if ((res = av_interleaved_write_frame(d->fmtContext, &pkt)) < 0) {
|
if ((res = av_interleaved_write_frame(d->fmtContext, &pkt)) < 0) {
|
||||||
LOG(("Audio Error: Unable to av_interleaved_write_frame for capture, error %1, %2").arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to av_interleaved_write_frame for capture, error %1, %2").arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
onStop(false);
|
onStop(false);
|
||||||
emit error();
|
emit error();
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
d->fullSamples += samplesCnt;
|
|
||||||
|
|
||||||
av_frame_free(&frame);
|
++written;
|
||||||
|
av_packet_unref(&pkt);
|
||||||
|
} while (true);
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FFMpegAttributesReader : public AbstractFFMpegLoader {
|
class FFMpegAttributesReader : public AbstractFFMpegLoader {
|
||||||
|
|
|
@ -264,6 +264,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AudioCapturePrivate;
|
struct AudioCapturePrivate;
|
||||||
|
struct AVFrame;
|
||||||
|
|
||||||
class AudioCaptureInner : public QObject {
|
class AudioCaptureInner : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -289,7 +290,13 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void writeFrame(int32 offset, int32 framesize);
|
void processFrame(int32 offset, int32 framesize);
|
||||||
|
|
||||||
|
void writeFrame(AVFrame *frame);
|
||||||
|
|
||||||
|
// Writes the packets till EAGAIN is got from av_receive_packet()
|
||||||
|
// Returns number of packets written or -1 on error
|
||||||
|
int writePackets();
|
||||||
|
|
||||||
AudioCapturePrivate *d;
|
AudioCapturePrivate *d;
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
|
|
|
@ -65,7 +65,7 @@ bool AbstractFFMpegLoader::open(qint64 &position) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
freq = fmtContext->streams[streamId]->codec->sample_rate;
|
freq = fmtContext->streams[streamId]->codecpar->sample_rate;
|
||||||
if (fmtContext->streams[streamId]->duration == AV_NOPTS_VALUE) {
|
if (fmtContext->streams[streamId]->duration == AV_NOPTS_VALUE) {
|
||||||
len = (fmtContext->duration * freq) / AV_TIME_BASE;
|
len = (fmtContext->duration * freq) / AV_TIME_BASE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,15 +145,26 @@ bool FFMpegLoader::open(qint64 &position) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
|
||||||
// Get a pointer to the codec context for the audio stream
|
auto codecParams = fmtContext->streams[streamId]->codecpar;
|
||||||
av_opt_set_int(fmtContext->streams[streamId]->codec, "refcounted_frames", 1, 0);
|
|
||||||
if ((res = avcodec_open2(fmtContext->streams[streamId]->codec, codec, 0)) < 0) {
|
codecContext = avcodec_alloc_context3(nullptr);
|
||||||
|
if (!codecContext) {
|
||||||
|
LOG(("Audio Error: Unable to avcodec_alloc_context3 for file '%1', data size '%2'").arg(file.name()).arg(data.size()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((res = avcodec_parameters_to_context(codecContext, codecParams)) < 0) {
|
||||||
|
LOG(("Audio Error: Unable to avcodec_parameters_to_context for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
av_codec_set_pkt_timebase(codecContext, fmtContext->streams[streamId]->time_base);
|
||||||
|
av_opt_set_int(codecContext, "refcounted_frames", 1, 0);
|
||||||
|
|
||||||
|
if ((res = avcodec_open2(codecContext, codec, 0)) < 0) {
|
||||||
LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
codecContext = fmtContext->streams[streamId]->codec;
|
|
||||||
|
|
||||||
uint64_t layout = codecContext->channel_layout;
|
uint64_t layout = codecParams->channel_layout;
|
||||||
inputFormat = codecContext->sample_fmt;
|
inputFormat = codecContext->sample_fmt;
|
||||||
switch (layout) {
|
switch (layout) {
|
||||||
case AV_CH_LAYOUT_MONO:
|
case AV_CH_LAYOUT_MONO:
|
||||||
|
@ -232,29 +243,51 @@ bool FFMpegLoader::open(qint64 &position) {
|
||||||
|
|
||||||
AudioPlayerLoader::ReadResult FFMpegLoader::readMore(QByteArray &result, int64 &samplesAdded) {
|
AudioPlayerLoader::ReadResult FFMpegLoader::readMore(QByteArray &result, int64 &samplesAdded) {
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
av_frame_unref(frame);
|
||||||
|
res = avcodec_receive_frame(codecContext, frame);
|
||||||
|
if (res >= 0) {
|
||||||
|
return readFromReadyFrame(result, samplesAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == AVERROR_EOF) {
|
||||||
|
return ReadResult::EndOfFile;
|
||||||
|
} else if (res != AVERROR(EAGAIN)) {
|
||||||
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
LOG(("Audio Error: Unable to avcodec_receive_frame() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
return ReadResult::Error;
|
||||||
|
}
|
||||||
|
|
||||||
if ((res = av_read_frame(fmtContext, &avpkt)) < 0) {
|
if ((res = av_read_frame(fmtContext, &avpkt)) < 0) {
|
||||||
if (res != AVERROR_EOF) {
|
if (res != AVERROR_EOF) {
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to av_read_frame() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to av_read_frame() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
return ReadResult::EndOfFile;
|
avcodec_send_packet(codecContext, nullptr); // drain
|
||||||
|
return ReadResult::Ok;
|
||||||
}
|
}
|
||||||
if (avpkt.stream_index == streamId) {
|
|
||||||
av_frame_unref(frame);
|
|
||||||
int got_frame = 0;
|
|
||||||
if ((res = avcodec_decode_audio4(codecContext, frame, &got_frame, &avpkt)) < 0) {
|
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
|
||||||
LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
|
||||||
|
|
||||||
|
if (avpkt.stream_index == streamId) {
|
||||||
|
res = avcodec_send_packet(codecContext, &avpkt);
|
||||||
|
if (res < 0) {
|
||||||
av_packet_unref(&avpkt);
|
av_packet_unref(&avpkt);
|
||||||
|
|
||||||
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
LOG(("Audio Error: Unable to avcodec_send_packet() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
if (res == AVERROR_INVALIDDATA) {
|
if (res == AVERROR_INVALIDDATA) {
|
||||||
return ReadResult::NotYet; // try to skip bad packet
|
return ReadResult::NotYet; // try to skip bad packet
|
||||||
}
|
}
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
av_packet_unref(&avpkt);
|
||||||
|
return ReadResult::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioPlayerLoader::ReadResult FFMpegLoader::readFromReadyFrame(QByteArray &result, int64 &samplesAdded) {
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
if (got_frame) {
|
|
||||||
if (dstSamplesData) { // convert needed
|
if (dstSamplesData) { // convert needed
|
||||||
int64_t dstSamples = av_rescale_rnd(swr_get_delay(swrContext, srcRate) + frame->nb_samples, dstRate, srcRate, AV_ROUND_UP);
|
int64_t dstSamples = av_rescale_rnd(swr_get_delay(swrContext, srcRate) + frame->nb_samples, dstRate, srcRate, AV_ROUND_UP);
|
||||||
if (dstSamples > maxResampleSamples) {
|
if (dstSamples > maxResampleSamples) {
|
||||||
|
@ -265,16 +298,12 @@ AudioPlayerLoader::ReadResult FFMpegLoader::readMore(QByteArray &result, int64 &
|
||||||
dstSamplesData[0] = 0;
|
dstSamplesData[0] = 0;
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
|
||||||
av_packet_unref(&avpkt);
|
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((res = swr_convert(swrContext, dstSamplesData, dstSamples, (const uint8_t**)frame->extended_data, frame->nb_samples)) < 0) {
|
if ((res = swr_convert(swrContext, dstSamplesData, dstSamples, (const uint8_t**)frame->extended_data, frame->nb_samples)) < 0) {
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
|
||||||
av_packet_unref(&avpkt);
|
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1);
|
int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1);
|
||||||
|
@ -284,14 +313,11 @@ AudioPlayerLoader::ReadResult FFMpegLoader::readMore(QByteArray &result, int64 &
|
||||||
result.append((const char*)frame->extended_data[0], frame->nb_samples * sampleSize);
|
result.append((const char*)frame->extended_data[0], frame->nb_samples * sampleSize);
|
||||||
samplesAdded += frame->nb_samples;
|
samplesAdded += frame->nb_samples;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
av_packet_unref(&avpkt);
|
|
||||||
return ReadResult::Ok;
|
return ReadResult::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
FFMpegLoader::~FFMpegLoader() {
|
FFMpegLoader::~FFMpegLoader() {
|
||||||
if (codecContext) avcodec_close(codecContext);
|
if (codecContext) avcodec_free_context(&codecContext);
|
||||||
if (swrContext) swr_free(&swrContext);
|
if (swrContext) swr_free(&swrContext);
|
||||||
if (dstSamplesData) {
|
if (dstSamplesData) {
|
||||||
if (dstSamplesData[0]) {
|
if (dstSamplesData[0]) {
|
||||||
|
|
|
@ -86,6 +86,8 @@ protected:
|
||||||
int32 sampleSize = 2 * sizeof(uint16);
|
int32 sampleSize = 2 * sizeof(uint16);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ReadResult readFromReadyFrame(QByteArray &result, int64 &samplesAdded);
|
||||||
|
|
||||||
int32 fmt = AL_FORMAT_STEREO16;
|
int32 fmt = AL_FORMAT_STEREO16;
|
||||||
int32 srcRate = AudioVoiceMsgFrequency;
|
int32 srcRate = AudioVoiceMsgFrequency;
|
||||||
int32 dstRate = AudioVoiceMsgFrequency;
|
int32 dstRate = AudioVoiceMsgFrequency;
|
||||||
|
|
|
@ -114,34 +114,53 @@ bool ChildFFMpegLoader::open(qint64 &position) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, int64 &samplesAdded) {
|
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, int64 &samplesAdded) {
|
||||||
|
int res;
|
||||||
|
|
||||||
|
av_frame_unref(_frame);
|
||||||
|
res = avcodec_receive_frame(_parentData->context, _frame);
|
||||||
|
if (res >= 0) {
|
||||||
|
return readFromReadyFrame(result, samplesAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == AVERROR_EOF) {
|
||||||
|
return ReadResult::EndOfFile;
|
||||||
|
} else if (res != AVERROR(EAGAIN)) {
|
||||||
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
LOG(("Audio Error: Unable to avcodec_receive_frame() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
return ReadResult::Error;
|
||||||
|
}
|
||||||
|
|
||||||
if (_queue.isEmpty()) {
|
if (_queue.isEmpty()) {
|
||||||
return _eofReached ? ReadResult::EndOfFile : ReadResult::Wait;
|
return _eofReached ? ReadResult::EndOfFile : ReadResult::Wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
av_frame_unref(_frame);
|
|
||||||
int got_frame = 0;
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
AVPacket packet;
|
AVPacket packet;
|
||||||
FFMpeg::packetFromDataWrap(packet, _queue.dequeue());
|
FFMpeg::packetFromDataWrap(packet, _queue.dequeue());
|
||||||
|
|
||||||
_eofReached = FFMpeg::isNullPacket(packet);
|
_eofReached = FFMpeg::isNullPacket(packet);
|
||||||
if (_eofReached) {
|
if (_eofReached) {
|
||||||
return ReadResult::EndOfFile;
|
avcodec_send_packet(_parentData->context, nullptr); // drain
|
||||||
|
return ReadResult::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res = avcodec_decode_audio4(_parentData->context, _frame, &got_frame, &packet)) < 0) {
|
res = avcodec_send_packet(_parentData->context, &packet);
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
if (res < 0) {
|
||||||
LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
|
||||||
|
|
||||||
FFMpeg::freePacket(&packet);
|
FFMpeg::freePacket(&packet);
|
||||||
|
|
||||||
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
LOG(("Audio Error: Unable to avcodec_send_packet() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
if (res == AVERROR_INVALIDDATA) {
|
if (res == AVERROR_INVALIDDATA) {
|
||||||
return ReadResult::NotYet; // try to skip bad packet
|
return ReadResult::NotYet; // try to skip bad packet
|
||||||
}
|
}
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
|
FFMpeg::freePacket(&packet);
|
||||||
|
return ReadResult::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readFromReadyFrame(QByteArray &result, int64 &samplesAdded) {
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
if (got_frame) {
|
|
||||||
if (_dstSamplesData) { // convert needed
|
if (_dstSamplesData) { // convert needed
|
||||||
int64_t dstSamples = av_rescale_rnd(swr_get_delay(_swrContext, _srcRate) + _frame->nb_samples, _dstRate, _srcRate, AV_ROUND_UP);
|
int64_t dstSamples = av_rescale_rnd(swr_get_delay(_swrContext, _srcRate) + _frame->nb_samples, _dstRate, _srcRate, AV_ROUND_UP);
|
||||||
if (dstSamples > _maxResampleSamples) {
|
if (dstSamples > _maxResampleSamples) {
|
||||||
|
@ -152,16 +171,12 @@ AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, in
|
||||||
_dstSamplesData[0] = 0;
|
_dstSamplesData[0] = 0;
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
|
||||||
FFMpeg::freePacket(&packet);
|
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((res = swr_convert(_swrContext, _dstSamplesData, dstSamples, (const uint8_t**)_frame->extended_data, _frame->nb_samples)) < 0) {
|
if ((res = swr_convert(_swrContext, _dstSamplesData, dstSamples, (const uint8_t**)_frame->extended_data, _frame->nb_samples)) < 0) {
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
|
||||||
FFMpeg::freePacket(&packet);
|
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1);
|
int32 resultLen = av_samples_get_buffer_size(0, AudioToChannels, res, AudioToFormat, 1);
|
||||||
|
@ -171,8 +186,6 @@ AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(QByteArray &result, in
|
||||||
result.append((const char*)_frame->extended_data[0], _frame->nb_samples * _sampleSize);
|
result.append((const char*)_frame->extended_data[0], _frame->nb_samples * _sampleSize);
|
||||||
samplesAdded += _frame->nb_samples;
|
samplesAdded += _frame->nb_samples;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
FFMpeg::freePacket(&packet);
|
|
||||||
return ReadResult::Ok;
|
return ReadResult::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,8 @@ public:
|
||||||
~ChildFFMpegLoader();
|
~ChildFFMpegLoader();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ReadResult readFromReadyFrame(QByteArray &result, int64 &samplesAdded);
|
||||||
|
|
||||||
bool _eofReached = false;
|
bool _eofReached = false;
|
||||||
|
|
||||||
int32 _sampleSize = 2 * sizeof(uint16);
|
int32 _sampleSize = 2 * sizeof(uint16);
|
||||||
|
|
|
@ -42,77 +42,14 @@ ReaderImplementation::ReadResult FFMpegReaderImplementation::readNextFrame() {
|
||||||
_frameRead = false;
|
_frameRead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
do {
|
||||||
while (_packetQueue.isEmpty()) {
|
int res = avcodec_receive_frame(_codecContext, _frame);
|
||||||
auto packetResult = readAndProcessPacket();
|
if (res >= 0) {
|
||||||
if (packetResult == PacketResult::Error) {
|
processReadFrame();
|
||||||
return ReadResult::Error;
|
|
||||||
} else if (packetResult == PacketResult::EndOfFile) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool eofReached = _packetQueue.isEmpty();
|
|
||||||
|
|
||||||
startPacket();
|
|
||||||
|
|
||||||
int got_frame = 0;
|
|
||||||
auto packet = &_packetNull;
|
|
||||||
AVPacket tempPacket;
|
|
||||||
if (!_packetQueue.isEmpty()) {
|
|
||||||
FFMpeg::packetFromDataWrap(tempPacket, _packetQueue.head());
|
|
||||||
packet = &tempPacket;
|
|
||||||
}
|
|
||||||
int decoded = packet->size;
|
|
||||||
|
|
||||||
int res = 0;
|
|
||||||
if ((res = avcodec_decode_video2(_codecContext, _frame, &got_frame, packet)) < 0) {
|
|
||||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
|
||||||
LOG(("Gif Error: Unable to avcodec_decode_video2() %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
|
||||||
|
|
||||||
if (res == AVERROR_INVALIDDATA) { // try to skip bad packet
|
|
||||||
finishPacket();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
eofReached = (res == AVERROR_EOF);
|
|
||||||
if (!eofReached || !_hadFrame) { // try to skip end of file
|
|
||||||
return ReadResult::Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (res > 0) decoded = res;
|
|
||||||
|
|
||||||
if (!_packetQueue.isEmpty()) {
|
|
||||||
packet->data += decoded;
|
|
||||||
packet->size -= decoded;
|
|
||||||
if (packet->size <= 0) {
|
|
||||||
finishPacket();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (got_frame) {
|
|
||||||
int64 duration = av_frame_get_pkt_duration(_frame);
|
|
||||||
int64 framePts = (_frame->pkt_pts == AV_NOPTS_VALUE) ? _frame->pkt_dts : _frame->pkt_pts;
|
|
||||||
int64 frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
|
|
||||||
_currentFrameDelay = _nextFrameDelay;
|
|
||||||
if (_frameMs + _currentFrameDelay < frameMs) {
|
|
||||||
_currentFrameDelay = int32(frameMs - _frameMs);
|
|
||||||
} else if (frameMs < _frameMs + _currentFrameDelay) {
|
|
||||||
frameMs = _frameMs + _currentFrameDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duration == AV_NOPTS_VALUE) {
|
|
||||||
_nextFrameDelay = 0;
|
|
||||||
} else {
|
|
||||||
_nextFrameDelay = (duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
|
|
||||||
}
|
|
||||||
_frameMs = frameMs;
|
|
||||||
|
|
||||||
_hadFrame = _frameRead = true;
|
|
||||||
_frameTime += _currentFrameDelay;
|
|
||||||
return ReadResult::Success;
|
return ReadResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eofReached) {
|
if (res == AVERROR_EOF) {
|
||||||
clearPacketQueue();
|
clearPacketQueue();
|
||||||
if (_mode == Mode::Normal) {
|
if (_mode == Mode::Normal) {
|
||||||
return ReadResult::Eof;
|
return ReadResult::Eof;
|
||||||
|
@ -133,10 +70,68 @@ ReaderImplementation::ReadResult FFMpegReaderImplementation::readNextFrame() {
|
||||||
_hadFrame = false;
|
_hadFrame = false;
|
||||||
_frameMs = 0;
|
_frameMs = 0;
|
||||||
_lastReadVideoMs = _lastReadAudioMs = 0;
|
_lastReadVideoMs = _lastReadAudioMs = 0;
|
||||||
}
|
|
||||||
|
continue;
|
||||||
|
} else if (res != AVERROR(EAGAIN)) {
|
||||||
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
LOG(("Audio Error: Unable to avcodec_receive_frame() %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
return ReadResult::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (_packetQueue.isEmpty()) {
|
||||||
|
auto packetResult = readAndProcessPacket();
|
||||||
|
if (packetResult == PacketResult::Error) {
|
||||||
return ReadResult::Error;
|
return ReadResult::Error;
|
||||||
|
} else if (packetResult == PacketResult::EndOfFile) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_packetQueue.isEmpty()) {
|
||||||
|
avcodec_send_packet(_codecContext, nullptr); // drain
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
startPacket();
|
||||||
|
|
||||||
|
AVPacket packet;
|
||||||
|
FFMpeg::packetFromDataWrap(packet, _packetQueue.head());
|
||||||
|
res = avcodec_send_packet(_codecContext, &packet);
|
||||||
|
if (res < 0) {
|
||||||
|
finishPacket();
|
||||||
|
|
||||||
|
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||||
|
LOG(("Audio Error: Unable to avcodec_send_packet() %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
if (res == AVERROR_INVALIDDATA) {
|
||||||
|
continue; // try to skip bad packet
|
||||||
|
}
|
||||||
|
return ReadResult::Error;
|
||||||
|
}
|
||||||
|
finishPacket();
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
return ReadResult::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FFMpegReaderImplementation::processReadFrame() {
|
||||||
|
int64 duration = av_frame_get_pkt_duration(_frame);
|
||||||
|
int64 framePts = (_frame->pkt_pts == AV_NOPTS_VALUE) ? _frame->pkt_dts : _frame->pkt_pts;
|
||||||
|
int64 frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
|
||||||
|
_currentFrameDelay = _nextFrameDelay;
|
||||||
|
if (_frameMs + _currentFrameDelay < frameMs) {
|
||||||
|
_currentFrameDelay = int32(frameMs - _frameMs);
|
||||||
|
} else if (frameMs < _frameMs + _currentFrameDelay) {
|
||||||
|
frameMs = _frameMs + _currentFrameDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration == AV_NOPTS_VALUE) {
|
||||||
|
_nextFrameDelay = 0;
|
||||||
|
} else {
|
||||||
|
_nextFrameDelay = (duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
|
||||||
|
}
|
||||||
|
_frameMs = frameMs;
|
||||||
|
|
||||||
|
_hadFrame = _frameRead = true;
|
||||||
|
_frameTime += _currentFrameDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReaderImplementation::ReadResult FFMpegReaderImplementation::readFramesTill(int64 frameMs, uint64 systemMs) {
|
ReaderImplementation::ReadResult FFMpegReaderImplementation::readFramesTill(int64 frameMs, uint64 systemMs) {
|
||||||
|
@ -291,8 +286,18 @@ bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) {
|
||||||
}
|
}
|
||||||
_packetNull.stream_index = _streamId;
|
_packetNull.stream_index = _streamId;
|
||||||
|
|
||||||
// Get a pointer to the codec context for the video stream
|
_codecContext = avcodec_alloc_context3(nullptr);
|
||||||
_codecContext = _fmtContext->streams[_streamId]->codec;
|
if (!_codecContext) {
|
||||||
|
LOG(("Audio Error: Unable to avcodec_alloc_context3 %1").arg(logData()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((res = avcodec_parameters_to_context(_codecContext, _fmtContext->streams[_streamId]->codecpar)) < 0) {
|
||||||
|
LOG(("Audio Error: Unable to avcodec_parameters_to_context %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
av_codec_set_pkt_timebase(_codecContext, _fmtContext->streams[_streamId]->time_base);
|
||||||
|
av_opt_set_int(_codecContext, "refcounted_frames", 1, 0);
|
||||||
|
|
||||||
_codec = avcodec_find_decoder(_codecContext->codec_id);
|
_codec = avcodec_find_decoder(_codecContext->codec_id);
|
||||||
|
|
||||||
_audioStreamId = av_find_best_stream(_fmtContext, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);
|
_audioStreamId = av_find_best_stream(_fmtContext, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);
|
||||||
|
@ -309,7 +314,7 @@ bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) {
|
||||||
} else if (_mode == Mode::Silent || !audioPlayer() || !_playId) {
|
} else if (_mode == Mode::Silent || !audioPlayer() || !_playId) {
|
||||||
_audioStreamId = -1;
|
_audioStreamId = -1;
|
||||||
}
|
}
|
||||||
av_opt_set_int(_codecContext, "refcounted_frames", 1, 0);
|
|
||||||
if ((res = avcodec_open2(_codecContext, _codec, 0)) < 0) {
|
if ((res = avcodec_open2(_codecContext, _codec, 0)) < 0) {
|
||||||
LOG(("Gif Error: Unable to avcodec_open2 %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Gif Error: Unable to avcodec_open2 %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
return false;
|
return false;
|
||||||
|
@ -317,16 +322,19 @@ bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) {
|
||||||
|
|
||||||
std_::unique_ptr<VideoSoundData> soundData;
|
std_::unique_ptr<VideoSoundData> soundData;
|
||||||
if (_audioStreamId >= 0) {
|
if (_audioStreamId >= 0) {
|
||||||
// Get a pointer to the codec context for the audio stream
|
AVCodecContext *audioContext = avcodec_alloc_context3(nullptr);
|
||||||
auto audioContextOriginal = _fmtContext->streams[_audioStreamId]->codec;
|
if (!audioContext) {
|
||||||
auto audioCodec = avcodec_find_decoder(audioContextOriginal->codec_id);
|
LOG(("Audio Error: Unable to avcodec_alloc_context3 %1").arg(logData()));
|
||||||
|
|
||||||
AVCodecContext *audioContext = avcodec_alloc_context3(audioCodec);
|
|
||||||
if ((res = avcodec_copy_context(audioContext, audioContextOriginal)) != 0) {
|
|
||||||
LOG(("Gif Error: Unable to avcodec_open2 %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ((res = avcodec_parameters_to_context(audioContext, _fmtContext->streams[_audioStreamId]->codecpar)) < 0) {
|
||||||
|
LOG(("Audio Error: Unable to avcodec_parameters_to_context %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
av_codec_set_pkt_timebase(audioContext, _fmtContext->streams[_audioStreamId]->time_base);
|
||||||
av_opt_set_int(audioContext, "refcounted_frames", 1, 0);
|
av_opt_set_int(audioContext, "refcounted_frames", 1, 0);
|
||||||
|
|
||||||
|
auto audioCodec = avcodec_find_decoder(audioContext->codec_id);
|
||||||
if ((res = avcodec_open2(audioContext, audioCodec, 0)) < 0) {
|
if ((res = avcodec_open2(audioContext, audioCodec, 0)) < 0) {
|
||||||
avcodec_free_context(&audioContext);
|
avcodec_free_context(&audioContext);
|
||||||
LOG(("Gif Error: Unable to avcodec_open2 %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
LOG(("Gif Error: Unable to avcodec_open2 %1, error %2, %3").arg(logData()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||||
|
@ -334,7 +342,7 @@ bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) {
|
||||||
} else {
|
} else {
|
||||||
soundData = std_::make_unique<VideoSoundData>();
|
soundData = std_::make_unique<VideoSoundData>();
|
||||||
soundData->context = audioContext;
|
soundData->context = audioContext;
|
||||||
soundData->frequency = audioContextOriginal->sample_rate;
|
soundData->frequency = _fmtContext->streams[_audioStreamId]->codecpar->sample_rate;
|
||||||
if (_fmtContext->streams[_audioStreamId]->duration == AV_NOPTS_VALUE) {
|
if (_fmtContext->streams[_audioStreamId]->duration == AV_NOPTS_VALUE) {
|
||||||
soundData->length = (_fmtContext->duration * soundData->frequency) / AV_TIME_BASE;
|
soundData->length = (_fmtContext->duration * soundData->frequency) / AV_TIME_BASE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -385,7 +393,7 @@ FFMpegReaderImplementation::~FFMpegReaderImplementation() {
|
||||||
av_frame_unref(_frame);
|
av_frame_unref(_frame);
|
||||||
_frameRead = false;
|
_frameRead = false;
|
||||||
}
|
}
|
||||||
if (_codecContext) avcodec_close(_codecContext);
|
if (_codecContext) avcodec_free_context(&_codecContext);
|
||||||
if (_swsContext) sws_freeContext(_swsContext);
|
if (_swsContext) sws_freeContext(_swsContext);
|
||||||
if (_opened) {
|
if (_opened) {
|
||||||
avformat_close_input(&_fmtContext);
|
avformat_close_input(&_fmtContext);
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReadResult readNextFrame();
|
ReadResult readNextFrame();
|
||||||
|
void processReadFrame();
|
||||||
|
|
||||||
enum class PacketResult {
|
enum class PacketResult {
|
||||||
Ok,
|
Ok,
|
||||||
|
|
|
@ -148,7 +148,7 @@ Open **VS2015 x86 Native Tools Command Prompt.bat** (should be in **Start Menu >
|
||||||
|
|
||||||
git clone https://github.com/FFmpeg/FFmpeg.git ffmpeg
|
git clone https://github.com/FFmpeg/FFmpeg.git ffmpeg
|
||||||
cd ffmpeg
|
cd ffmpeg
|
||||||
git checkout release/2.8
|
git checkout release/3.1
|
||||||
|
|
||||||
http://msys2.github.io/ > Download [msys2-x86_64-20150512.exe](http://sourceforge.net/projects/msys2/files/Base/x86_64/msys2-x86_64-20150512.exe/download) and install to **D:\\msys64**
|
http://msys2.github.io/ > Download [msys2-x86_64-20150512.exe](http://sourceforge.net/projects/msys2/files/Base/x86_64/msys2-x86_64-20150512.exe/download) and install to **D:\\msys64**
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ Open **VS2015 x86 Native Tools Command Prompt.bat** (should be in **Start Menu >
|
||||||
|
|
||||||
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
|
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||||
|
|
||||||
./configure --toolchain=msvc --disable-programs --disable-doc --disable-everything --disable-w32threads --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wavpack --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_d3d11va --enable-hwaccel=h264_dxva2 --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-ldflags="-libpath:/d/TBuild/Libraries/opus/win32/VS2010/Win32/Release celt.lib silk_common.lib silk_float.lib"
|
./configure --toolchain=msvc --disable-programs --disable-doc --disable-everything --enable-protocol=file --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wavpack --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_d3d11va --enable-hwaccel=h264_dxva2 --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-ldflags="-libpath:/d/TBuild/Libraries/opus/win32/VS2010/Win32/Release celt.lib silk_common.lib silk_float.lib"
|
||||||
|
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
|
|
|
@ -69,13 +69,13 @@ In Terminal go to **/home/user/TBuild/Libraries** and run
|
||||||
|
|
||||||
git clone https://github.com/FFmpeg/FFmpeg.git ffmpeg
|
git clone https://github.com/FFmpeg/FFmpeg.git ffmpeg
|
||||||
cd ffmpeg
|
cd ffmpeg
|
||||||
git checkout release/2.8
|
git checkout release/3.1
|
||||||
|
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -y --force-yes install autoconf automake build-essential libass-dev libfreetype6-dev libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texi2html zlib1g-dev
|
sudo apt-get -y --force-yes install autoconf automake build-essential libass-dev libfreetype6-dev libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texi2html zlib1g-dev
|
||||||
sudo apt-get install yasm
|
sudo apt-get install yasm
|
||||||
|
|
||||||
./configure --prefix=/usr/local --disable-programs --disable-doc --disable-pthreads --disable-mmx --disable-everything --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vdpau --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=mpeg4_vdpau --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vdpau --enable-hwaccel=mpeg4_vaapi --enable-hwaccel=mpeg4_vdpau --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus
|
./configure --prefix=/usr/local --disable-programs --disable-doc --disable-everything --enable-protocol=file --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vdpau --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=mpeg4_vdpau --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vdpau --enable-hwaccel=mpeg4_vaapi --enable-hwaccel=mpeg4_vdpau --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus
|
||||||
|
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
|
@ -153,7 +153,7 @@ Then in Terminal go to **/Users/user/TBuild/Libraries/ffmpeg** and run
|
||||||
LDFLAGS=`freetype-config --libs`
|
LDFLAGS=`freetype-config --libs`
|
||||||
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:/usr/X11/lib/pkgconfig
|
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:/usr/X11/lib/pkgconfig
|
||||||
|
|
||||||
./configure --prefix=/usr/local/ffmpeg_old --disable-programs --disable-doc --disable-everything --disable-pthreads --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-cflags="-mmacosx-version-min=10.6" --extra-cxxflags="-mmacosx-version-min=10.6" --extra-ldflags="-mmacosx-version-min=10.6"
|
./configure --prefix=/usr/local/ffmpeg_old --disable-programs --disable-doc --disable-everything --enable-protocol=file --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-cflags="-mmacosx-version-min=10.6" --extra-cxxflags="-mmacosx-version-min=10.6" --extra-ldflags="-mmacosx-version-min=10.6"
|
||||||
|
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
|
@ -187,7 +187,7 @@ Then in Terminal go to **/Users/user/TBuild/Libraries/ffmpeg** and run:
|
||||||
LDFLAGS=`freetype-config --libs`
|
LDFLAGS=`freetype-config --libs`
|
||||||
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:/usr/X11/lib/pkgconfig
|
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:/usr/X11/lib/pkgconfig
|
||||||
|
|
||||||
./configure --prefix=/usr/local --disable-programs --disable-doc --disable-everything --disable-pthreads --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vda --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=mpeg4_videotoolbox --enable-hwaccel=h264_vda --enable-hwaccel=h264_videotoolbox --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-cflags="-mmacosx-version-min=10.8" --extra-cxxflags="-mmacosx-version-min=10.8" --extra-ldflags="-mmacosx-version-min=10.8"
|
./configure --prefix=/usr/local --disable-programs --disable-doc --disable-everything --enable-protocol=file --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vda --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=mpeg4_videotoolbox --enable-hwaccel=h264_vda --enable-hwaccel=h264_videotoolbox --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-cflags="-mmacosx-version-min=10.8" --extra-cxxflags="-mmacosx-version-min=10.8" --extra-ldflags="-mmacosx-version-min=10.8"
|
||||||
|
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
Loading…
Reference in New Issue