MKVPlayer.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #pragma once
  2. #include <windows.h>
  3. #include <bfc/platform/types.h>
  4. // nsmkv stuff
  5. #include "../nsmkv/Cluster.h"
  6. #include "../nsmkv/header.h"
  7. #include "../nsmkv/SeekTable.h"
  8. #include "../nsmkv/SegmentInfo.h"
  9. #include "../nsmkv/Tracks.h"
  10. #include "../nsmkv/Cues.h"
  11. #include "../nsmkv/Attachments.h"
  12. #include "../nsmkv/mkv_reader.h"
  13. #include "ifc_mkvvideodecoder.h"
  14. #include "ifc_mkvaudiodecoder.h"
  15. #include "../nu/AutoLock.h"
  16. #include "../nu/AudioOutput.h"
  17. class MKVPlayer
  18. {
  19. public:
  20. MKVPlayer(const wchar_t *_filename);
  21. ~MKVPlayer();
  22. DWORD CALLBACK ThreadFunction();
  23. DWORD CALLBACK VideoThreadFunction();
  24. void Kill();
  25. void Seek(int seek_pos);
  26. int GetOutputTime() const;
  27. private:
  28. // subfunctions to make the code cleaner
  29. // they all have "side effects", which is a coding style I don't like
  30. // but it makes it easier to read & modify
  31. // TODO: move these to step, and have a state variable to know where we are
  32. bool ParseHeader(); // on completion, header will be filled, file pointer will be at next level 0 node
  33. bool FindSegment(); // on completion, segment_position will be calculated, file pointer will be at first level 1 node under segment
  34. // file position is restored at end of function
  35. bool FindCues();
  36. int ParseCluster(nsmkv::MKVReader *stream, uint64_t size, uint64_t *track_numbers, size_t track_numbers_len);
  37. enum
  38. {
  39. // values that you can return from OnXXXX()
  40. MKV_CONTINUE = 0, // continue processing
  41. MKV_ABORT = 1, // abort parsing gracefully (maybe 'stop' was pressed)
  42. MKV_STOP = 2, // stop parsing completely - usually returned when mkv version is too new or codecs not supported
  43. // values returned from errors within the Step() function itself
  44. MKV_EOF = 3, // end of file
  45. MKV_ERROR = 4, // parsing error
  46. };
  47. int OnHeader(const nsmkv::Header &header);
  48. void OnSegmentInfo(const nsmkv::SegmentInfo &segment_info);
  49. int OnTracks(const nsmkv::Tracks &tracks);
  50. int OnBlock(const nsmkv::Cluster &cluster, const nsmkv::Block &block);
  51. int OnFirstCluster(uint64_t position);
  52. int OnAudio(const nsmkv::Cluster &cluster, const nsmkv::BlockBinary &binary);
  53. int OnVideo(const nsmkv::Cluster &cluster, const nsmkv::BlockBinary &binary);
  54. int OutputPictures(uint64_t default_timestamp);
  55. /* start calling with cluster_number = 0 and block_number = 0 (or whatever appropriate based on CuePoints when seeking
  56. will return 0 on success, 1 on EOF and -1 on failure
  57. */
  58. int GetBlock(nsmkv::MKVReader *stream, uint64_t track_number, nsmkv::BlockBinary &binary, const nsmkv::Cluster **cluster, size_t &cluster_number, size_t &block_number);
  59. static void CALLBACK SeekAPC(ULONG_PTR data);
  60. int Step(nsmkv::MKVReader *stream, uint64_t *track_numbers, size_t track_numbers_len); // only gives you block data for the passed track number
  61. private:
  62. /* nsmkv internal implementation */
  63. nsmkv::Header header;
  64. uint64_t segment_position; // position of the start of the first level 1 element in the segment(for SeekHead relative positions)
  65. uint64_t segment_size; // size of that segment
  66. nsmkv::SeekTable seek_table;
  67. nsmkv::SegmentInfo segment_info;
  68. nsmkv::Tracks tracks;
  69. nsmkv::Clusters clusters;
  70. nsmkv::Cues cues;
  71. nsmkv::Attachments attachments;
  72. bool cues_searched;
  73. bool first_cluster_found;
  74. /* player implementation */
  75. nsmkv::MKVReader *main_reader; // also gets used as audio_stream
  76. Nullsoft::Utility::LockGuard cluster_guard;
  77. HANDLE killswitch, seek_event;
  78. wchar_t *filename;
  79. volatile int m_needseek;
  80. /* Audio */
  81. ifc_mkvaudiodecoder *audio_decoder;
  82. bool audio_opened;
  83. uint64_t audio_track_num;
  84. uint8_t audio_buffer[65536]; // TODO: dynamically allocate from OutputFrameSize
  85. size_t audio_output_len;
  86. size_t audio_buffered;
  87. int audio_first_timestamp;
  88. enum FlushState
  89. {
  90. FLUSH_NONE=0,
  91. FLUSH_START=1,
  92. FLUSH_SEEK=2,
  93. };
  94. FlushState audio_flushing;
  95. unsigned int audio_bitrate;
  96. /* Video */
  97. ifc_mkvvideodecoder *video_decoder;
  98. const nsmkv::TrackEntry *video_track_entry;
  99. bool video_opened;
  100. HANDLE video_thread;
  101. double video_timecode_scale;
  102. uint64_t video_track_num;
  103. uint64_t video_cluster_position;
  104. nsmkv::MKVReader *video_stream;
  105. HANDLE video_break, video_flush, video_flush_done, video_resume, video_ready;
  106. unsigned int video_bitrate;
  107. int consecutive_early_frames;
  108. /* AudioOutput implementation */
  109. class MKVWait
  110. {
  111. public:
  112. void Wait_SetEvents(HANDLE killswitch, HANDLE seek_event);
  113. protected:
  114. int WaitOrAbort(int time_in_ms);
  115. private:
  116. HANDLE handles[2];
  117. };
  118. nu::AudioOutput<MKVWait> audio_output;
  119. };