1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "media/clip/media_clip_implementation.h"
11 #include "ffmpeg/ffmpeg_utility.h"
12 
13 extern "C" {
14 #include <libswscale/swscale.h>
15 #include <libavutil/opt.h>
16 } // extern "C"
17 #include <deque>
18 
19 //#include "media/streaming/media_streaming_utility.h"
20 
21 namespace Media {
22 namespace Clip {
23 namespace internal {
24 
25 constexpr auto kMaxInMemory = 10 * 1024 * 1024;
26 
27 class FFMpegReaderImplementation : public ReaderImplementation {
28 public:
29 	FFMpegReaderImplementation(Core::FileLocation *location, QByteArray *data);
30 
31 	ReadResult readFramesTill(crl::time frameMs, crl::time systemMs) override;
32 
33 	crl::time frameRealTime() const override;
34 	crl::time framePresentationTime() const override;
35 
36 	bool renderFrame(QImage &to, bool &hasAlpha, const QSize &size) override;
37 
38 	crl::time durationMs() const override;
39 
40 	bool start(Mode mode, crl::time &positionMs) override;
41 	bool inspectAt(crl::time &positionMs);
42 
43 	QString logData() const;
44 
45 	bool isGifv() const;
46 
47 	~FFMpegReaderImplementation();
48 
49 private:
50 	ReadResult readNextFrame();
51 	void processReadFrame();
52 
53 	enum class PacketResult {
54 		Ok,
55 		EndOfFile,
56 		Error,
57 	};
58 	PacketResult readPacket(FFmpeg::Packet &packet);
59 	void processPacket(FFmpeg::Packet &&packet);
60 	crl::time countPacketMs(const FFmpeg::Packet &packet) const;
61 	PacketResult readAndProcessPacket();
62 
63 	enum class Rotation {
64 		None,
65 		Degrees90,
66 		Degrees180,
67 		Degrees270,
68 	};
69 	Rotation rotationFromDegrees(int degrees) const;
rotationSwapWidthHeight()70 	bool rotationSwapWidthHeight() const {
71 		return (_rotation == Rotation::Degrees90) || (_rotation == Rotation::Degrees270);
72 	}
73 
74 	static int _read(void *opaque, uint8_t *buf, int buf_size);
75 	static int64_t _seek(void *opaque, int64_t offset, int whence);
76 
77 	Mode _mode = Mode::Silent;
78 
79 	Rotation _rotation = Rotation::None;
80 
81 	uchar *_ioBuffer = nullptr;
82 	AVIOContext *_ioContext = nullptr;
83 	AVFormatContext *_fmtContext = nullptr;
84 	AVCodecContext *_codecContext = nullptr;
85 	int _streamId = 0;
86 	FFmpeg::FramePointer _frame;
87 	bool _opened = false;
88 	bool _hadFrame = false;
89 	bool _frameRead = false;
90 	int _skippedInvalidDataPackets = 0;
91 
92 	bool _hasAudioStream = false;
93 	crl::time _lastReadVideoMs = 0;
94 	crl::time _lastReadAudioMs = 0;
95 
96 	std::deque<FFmpeg::Packet> _packetQueue;
97 
98 	int _width = 0;
99 	int _height = 0;
100 	SwsContext *_swsContext = nullptr;
101 	QSize _swsSize;
102 
103 	crl::time _frameMs = 0;
104 	int _nextFrameDelay = 0;
105 	int _currentFrameDelay = 0;
106 
107 	crl::time _frameTime = 0;
108 	crl::time _frameTimeCorrection = 0;
109 
110 };
111 
112 } // namespace internal
113 } // namespace Clip
114 } // namespace Media
115