OXYGENHUB
◆ main openmsx / src / laserdisc / OggReader.hh
3.2 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef OGGREADER_HH
2
#define OGGREADER_HH
3
4
#include "File.hh"
5
6
#include "circular_buffer.hh"
7
#include "narrow.hh"
8
9
#include <ogg/ogg.h>
10
#include <theora/theoradec.h>
11
#include <vorbis/codec.h>
12
13
#include <array>
14
#include <cstdint>
15
#include <list>
16
#include <memory>
17
#include <string>
18
#include <vector>
19
20
namespace openmsx {
21
22
class CliComm;
23
class RawFrame;
24
25
struct AudioFragment
26
{
27
	static constexpr size_t UNKNOWN_POS = size_t(-1);
28
	static constexpr unsigned MAX_SAMPLES = 2048;
29
	size_t position;
30
	unsigned length;
31
	std::array<std::array<float, MAX_SAMPLES>, 2> pcm;
32
};
33
34
struct Frame
35
{
36
	explicit Frame(const th_ycbcr_buffer& yuv);
37
	Frame(const Frame&) = delete;
38
	Frame(Frame&&) = delete;
39
	Frame& operator=(const Frame&) = delete;
40
	Frame& operator=(Frame&&) = delete;
41
	~Frame();
42
43
	th_ycbcr_buffer buffer;
44
	size_t no;
45
	int length;
46
};
47
48
class OggReader
49
{
50
public:
51
	OggReader(const std::string& filename, CliComm& cli);
52
	OggReader(const OggReader&) = delete;
53
	OggReader(OggReader&&) = delete;
54
	OggReader& operator=(const OggReader&) = delete;
55
	OggReader& operator=(OggReader&&) = delete;
56
	~OggReader();
57
58
	bool seek(size_t frame, size_t sample);
59
	[[nodiscard]] unsigned getSampleRate() const { return narrow<unsigned>(vi.rate); }
60
	void getFrameNo(RawFrame& frame, size_t frameno);
61
	[[nodiscard]] const AudioFragment* getAudio(size_t sample);
62
	[[nodiscard]] size_t getFrames() const { return totalFrames; }
63
	[[nodiscard]] int getFrameRate() const { return frameRate; }
64
65
	// metadata
66
	[[nodiscard]] bool stopFrame(size_t frame) const;
67
	[[nodiscard]] size_t getChapter(int chapterNo) const;
68
69
private:
70
	void cleanup();
71
	void readTheora(ogg_packet* packet);
72
	void theoraHeaderPage(ogg_page* page, th_info& ti, th_comment& tc,
73
	                      th_setup_info*& tsi);
74
	void readMetadata(th_comment& tc);
75
	void readVorbis(ogg_packet* packet);
76
	void vorbisHeaderPage(ogg_page* page);
77
	bool nextPage(ogg_page* page);
78
	bool nextPacket();
79
	void recycleAudio(std::unique_ptr<AudioFragment> audio);
80
	void vorbisFoundPosition();
81
	size_t frameNo(const ogg_packet* packet) const;
82
83
	size_t findOffset(size_t frame, size_t sample);
84
	size_t bisection(size_t frame, size_t sample,
85
	                 size_t maxOffset, size_t maxSamples, size_t maxFrames);
86
87
private:
88
	CliComm& cli;
89
	File file;
90
91
	enum State : uint8_t {
92
		PLAYING,
93
		FIND_LAST,
94
		FIND_FIRST,
95
		FIND_KEYFRAME
96
	} state{PLAYING};
97
98
	// ogg state
99
	ogg_sync_state sync;
100
	ogg_stream_state vorbisStream, theoraStream;
101
	int audioSerial{-1};
102
	int videoSerial{-1};
103
	int skeletonSerial{-1};
104
	size_t fileOffset{0};
105
	size_t fileSize;
106
107
	// video
108
	th_dec_ctx* theora{nullptr};
109
	int frameRate;
110
	size_t keyFrame{size_t(-1)};
111
	size_t currentFrame{1};
112
	int granuleShift;
113
	size_t totalFrames;
114
115
	cb_queue<std::unique_ptr<Frame>> frameList;
116
	std::vector<std::unique_ptr<Frame>> recycleFrameList;
117
118
	// audio
119
	int audioHeaders{3};
120
	vorbis_info vi;
121
	vorbis_comment vc;
122
	vorbis_dsp_state vd;
123
	vorbis_block vb;
124
	size_t currentSample{0};
125
	size_t vorbisPos{0};
126
127
	std::list<std::unique_ptr<AudioFragment>> audioList;
128
	cb_queue<std::unique_ptr<AudioFragment>> recycleAudioList;
129
130
	// Metadata
131
	std::vector<size_t> stopFrames;
132
	struct ChapterFrame {
133
		int chapter;
134
		size_t frame;
135
	};
136
	std::vector<ChapterFrame> chapters; // sorted on chapter
137
};
138
139
} // namespace openmsx
140
141
#endif