104 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
This file is part of Telegram Desktop,
 | 
						|
the official desktop application for the Telegram messaging service.
 | 
						|
 | 
						|
For license and copyright information please follow this link:
 | 
						|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
						|
*/
 | 
						|
#include "media/media_child_ffmpeg_loader.h"
 | 
						|
 | 
						|
#include "core/crash_reports.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
constexpr AVSampleFormat AudioToFormat = AV_SAMPLE_FMT_S16;
 | 
						|
constexpr int64_t AudioToChannelLayout = AV_CH_LAYOUT_STEREO;
 | 
						|
constexpr int32 AudioToChannels = 2;
 | 
						|
 | 
						|
bool IsPlanarFormat(int format) {
 | 
						|
	return (format == AV_SAMPLE_FMT_U8P)
 | 
						|
		|| (format == AV_SAMPLE_FMT_S16P)
 | 
						|
		|| (format == AV_SAMPLE_FMT_S32P)
 | 
						|
		|| (format == AV_SAMPLE_FMT_FLTP)
 | 
						|
		|| (format == AV_SAMPLE_FMT_DBLP)
 | 
						|
		|| (format == AV_SAMPLE_FMT_S64P);
 | 
						|
}
 | 
						|
 | 
						|
} // namespace
 | 
						|
 | 
						|
VideoSoundData::~VideoSoundData() {
 | 
						|
	if (context) {
 | 
						|
		avcodec_close(context);
 | 
						|
		avcodec_free_context(&context);
 | 
						|
		context = nullptr;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
ChildFFMpegLoader::ChildFFMpegLoader(std::unique_ptr<VideoSoundData> &&data)
 | 
						|
: AbstractAudioFFMpegLoader(
 | 
						|
	FileLocation(),
 | 
						|
	QByteArray(),
 | 
						|
	bytes::vector())
 | 
						|
, _parentData(std::move(data)) {
 | 
						|
}
 | 
						|
 | 
						|
bool ChildFFMpegLoader::open(TimeMs positionMs) {
 | 
						|
	return initUsingContext(
 | 
						|
		_parentData->context,
 | 
						|
		_parentData->length,
 | 
						|
		_parentData->frequency);
 | 
						|
}
 | 
						|
 | 
						|
AudioPlayerLoader::ReadResult ChildFFMpegLoader::readMore(
 | 
						|
		QByteArray &result,
 | 
						|
		int64 &samplesAdded) {
 | 
						|
	const auto readResult = readFromReadyContext(
 | 
						|
		_parentData->context,
 | 
						|
		result,
 | 
						|
		samplesAdded);
 | 
						|
	if (readResult != ReadResult::Wait) {
 | 
						|
		return readResult;
 | 
						|
	}
 | 
						|
 | 
						|
	if (_queue.isEmpty()) {
 | 
						|
		return _eofReached ? ReadResult::EndOfFile : ReadResult::Wait;
 | 
						|
	}
 | 
						|
 | 
						|
	AVPacket packet;
 | 
						|
	FFMpeg::packetFromDataWrap(packet, _queue.dequeue());
 | 
						|
 | 
						|
	_eofReached = FFMpeg::isNullPacket(packet);
 | 
						|
	if (_eofReached) {
 | 
						|
		avcodec_send_packet(_parentData->context, nullptr); // drain
 | 
						|
		return ReadResult::Ok;
 | 
						|
	}
 | 
						|
 | 
						|
	auto res = avcodec_send_packet(_parentData->context, &packet);
 | 
						|
	if (res < 0) {
 | 
						|
		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)));
 | 
						|
		// There is a sample voice message where skipping such packet
 | 
						|
		// results in a crash (read_access to nullptr) in swr_convert().
 | 
						|
		if (res == AVERROR_INVALIDDATA) {
 | 
						|
			return ReadResult::NotYet; // try to skip bad packet
 | 
						|
		}
 | 
						|
		return ReadResult::Error;
 | 
						|
	}
 | 
						|
	FFMpeg::freePacket(&packet);
 | 
						|
	return ReadResult::Ok;
 | 
						|
}
 | 
						|
 | 
						|
void ChildFFMpegLoader::enqueuePackets(QQueue<FFMpeg::AVPacketDataWrap> &packets) {
 | 
						|
	_queue += std::move(packets);
 | 
						|
	packets.clear();
 | 
						|
}
 | 
						|
 | 
						|
ChildFFMpegLoader::~ChildFFMpegLoader() {
 | 
						|
	for (auto &packetData : base::take(_queue)) {
 | 
						|
		AVPacket packet;
 | 
						|
		FFMpeg::packetFromDataWrap(packet, packetData);
 | 
						|
		FFMpeg::freePacket(&packet);
 | 
						|
	}
 | 
						|
}
 |