diff options
Diffstat (limited to 'Src/Plugins/Input/in_mkv/MKVPlayer.h')
-rw-r--r-- | Src/Plugins/Input/in_mkv/MKVPlayer.h | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_mkv/MKVPlayer.h b/Src/Plugins/Input/in_mkv/MKVPlayer.h new file mode 100644 index 00000000..91de5122 --- /dev/null +++ b/Src/Plugins/Input/in_mkv/MKVPlayer.h @@ -0,0 +1,138 @@ +#pragma once +#include <windows.h> +#include <bfc/platform/types.h> + +// nsmkv stuff +#include "../nsmkv/Cluster.h" +#include "../nsmkv/header.h" +#include "../nsmkv/SeekTable.h" +#include "../nsmkv/SegmentInfo.h" +#include "../nsmkv/Tracks.h" +#include "../nsmkv/Cues.h" +#include "../nsmkv/Attachments.h" +#include "../nsmkv/mkv_reader.h" + +#include "ifc_mkvvideodecoder.h" +#include "ifc_mkvaudiodecoder.h" + +#include "../nu/AutoLock.h" +#include "../nu/AudioOutput.h" + + +class MKVPlayer +{ +public: + MKVPlayer(const wchar_t *_filename); + ~MKVPlayer(); + DWORD CALLBACK ThreadFunction(); + DWORD CALLBACK VideoThreadFunction(); + + void Kill(); + void Seek(int seek_pos); + int GetOutputTime() const; + +private: + // subfunctions to make the code cleaner + // they all have "side effects", which is a coding style I don't like + // but it makes it easier to read & modify + // TODO: move these to step, and have a state variable to know where we are + bool ParseHeader(); // on completion, header will be filled, file pointer will be at next level 0 node + bool FindSegment(); // on completion, segment_position will be calculated, file pointer will be at first level 1 node under segment + + // file position is restored at end of function + bool FindCues(); + + int ParseCluster(nsmkv::MKVReader *stream, uint64_t size, uint64_t *track_numbers, size_t track_numbers_len); + + enum + { + // values that you can return from OnXXXX() + MKV_CONTINUE = 0, // continue processing + MKV_ABORT = 1, // abort parsing gracefully (maybe 'stop' was pressed) + MKV_STOP = 2, // stop parsing completely - usually returned when mkv version is too new or codecs not supported + + // values returned from errors within the Step() function itself + MKV_EOF = 3, // end of file + MKV_ERROR = 4, // parsing error + }; + int OnHeader(const nsmkv::Header &header); + void OnSegmentInfo(const nsmkv::SegmentInfo &segment_info); + int OnTracks(const nsmkv::Tracks &tracks); + int OnBlock(const nsmkv::Cluster &cluster, const nsmkv::Block &block); + int OnFirstCluster(uint64_t position); + int OnAudio(const nsmkv::Cluster &cluster, const nsmkv::BlockBinary &binary); + int OnVideo(const nsmkv::Cluster &cluster, const nsmkv::BlockBinary &binary); + + int OutputPictures(uint64_t default_timestamp); + /* start calling with cluster_number = 0 and block_number = 0 (or whatever appropriate based on CuePoints when seeking + will return 0 on success, 1 on EOF and -1 on failure + */ + int GetBlock(nsmkv::MKVReader *stream, uint64_t track_number, nsmkv::BlockBinary &binary, const nsmkv::Cluster **cluster, size_t &cluster_number, size_t &block_number); + static void CALLBACK SeekAPC(ULONG_PTR data); + + int Step(nsmkv::MKVReader *stream, uint64_t *track_numbers, size_t track_numbers_len); // only gives you block data for the passed track number + +private: + /* nsmkv internal implementation */ + nsmkv::Header header; + uint64_t segment_position; // position of the start of the first level 1 element in the segment(for SeekHead relative positions) + uint64_t segment_size; // size of that segment + nsmkv::SeekTable seek_table; + nsmkv::SegmentInfo segment_info; + nsmkv::Tracks tracks; + nsmkv::Clusters clusters; + nsmkv::Cues cues; + nsmkv::Attachments attachments; + bool cues_searched; + bool first_cluster_found; + + /* player implementation */ + nsmkv::MKVReader *main_reader; // also gets used as audio_stream + Nullsoft::Utility::LockGuard cluster_guard; + HANDLE killswitch, seek_event; + wchar_t *filename; + volatile int m_needseek; + + /* Audio */ + ifc_mkvaudiodecoder *audio_decoder; + bool audio_opened; + uint64_t audio_track_num; + uint8_t audio_buffer[65536]; // TODO: dynamically allocate from OutputFrameSize + size_t audio_output_len; + size_t audio_buffered; + int audio_first_timestamp; + enum FlushState + { + FLUSH_NONE=0, + FLUSH_START=1, + FLUSH_SEEK=2, + }; + FlushState audio_flushing; + unsigned int audio_bitrate; + + /* Video */ + ifc_mkvvideodecoder *video_decoder; + const nsmkv::TrackEntry *video_track_entry; + bool video_opened; + HANDLE video_thread; + double video_timecode_scale; + uint64_t video_track_num; + uint64_t video_cluster_position; + nsmkv::MKVReader *video_stream; + HANDLE video_break, video_flush, video_flush_done, video_resume, video_ready; + unsigned int video_bitrate; + int consecutive_early_frames; + + /* AudioOutput implementation */ + class MKVWait + { + public: + void Wait_SetEvents(HANDLE killswitch, HANDLE seek_event); + protected: + int WaitOrAbort(int time_in_ms); + private: + HANDLE handles[2]; + }; + nu::AudioOutput<MKVWait> audio_output; + +};
\ No newline at end of file |