| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 131 |
std::vector<size_t> stopFrames; |
| 132 |
struct ChapterFrame { |
| 133 |
int chapter; |
| 134 |
size_t frame; |
| 135 |
}; |
| 136 |
std::vector<ChapterFrame> chapters; |
| 137 |
}; |
| 138 |
|
| 139 |
} |
| 140 |
|
| 141 |
#endif |