1
0

ExtendedRead.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #include <stddef.h>
  2. #include "main.h"
  3. #include "mpeg4audio.h"
  4. #include "api__in_mp4.h"
  5. #include <api/service/waservicefactory.h>
  6. #include <assert.h>
  7. #include "../nu/GaplessRingBuffer.h"
  8. #include "virtualIO.h"
  9. struct ExtendedRead
  10. {
  11. ExtendedRead() : mp4(0), mp4track(0), sampleId(1),
  12. samples(0), audio(0), audioFactory(0), frameSize(0), reader(0),
  13. sample_rate(0), timescale(0), max_sample_size(0), sample_buffer(0), decode_buffer(0)
  14. {}
  15. ~ExtendedRead()
  16. {
  17. if (mp4) MP4Close(mp4); mp4 = 0;
  18. if (reader) DestroyUnicodeReader(reader); reader=0;
  19. if (audio)
  20. {
  21. audio->Close();
  22. audioFactory->releaseInterface(audio);
  23. }
  24. audioFactory = 0;
  25. audio = 0;
  26. free(sample_buffer);
  27. sample_buffer=0;
  28. free(decode_buffer);
  29. }
  30. bool Open(const wchar_t *fn, int *size, int *bps, int *nch, int *srate, bool useFloat);
  31. MP4AudioDecoder *audio;
  32. MP4FileHandle mp4;
  33. MP4TrackId mp4track;
  34. MP4SampleId sampleId, samples;
  35. GaplessRingBuffer ringBuffer;
  36. void *reader;
  37. waServiceFactory *audioFactory;
  38. size_t frameSize;
  39. unsigned int sample_rate;
  40. uint32_t timescale;
  41. uint32_t max_sample_size;
  42. void *sample_buffer;
  43. uint8_t *decode_buffer;
  44. };
  45. bool ExtendedRead::Open(const wchar_t *fn, int *size, int *bps, int *nch, int *srate, bool useFloat)
  46. {
  47. unsigned __int32 pregap, postgap;
  48. int numBits = *bps;
  49. int numChannels = *nch;
  50. reader = CreateUnicodeReader(fn);
  51. if (!reader)
  52. return false;
  53. mp4 = MP4ReadEx(fn, reader, &UnicodeIO);
  54. if (!mp4)
  55. {
  56. DestroyUnicodeReader(reader);
  57. return false;
  58. }
  59. mp4track = GetAudioTrack(mp4);
  60. if (mp4track == MP4_INVALID_TRACK_ID) return false;
  61. if (!CreateDecoder(mp4, mp4track, audio, audioFactory))
  62. return false;
  63. int result;
  64. result = audio->OpenMP4(mp4, mp4track, numBits, numChannels, useFloat);
  65. if (result != MP4_SUCCESS)
  66. return false;
  67. GetGaps(mp4, pregap, postgap);
  68. ConfigureDecoderASC(mp4, mp4track, audio);
  69. timescale = MP4GetTrackTimeScale(mp4, mp4track);
  70. samples = MP4GetTrackNumberOfSamples(mp4, mp4track);
  71. MP4SampleId sample = 0;
  72. // some codecs require a frame or two to get decoded. so we'll go until GetOutputProperties is valid
  73. for (MP4SampleId sample = 1;sample <= samples; sample++)
  74. {
  75. int ret;
  76. if (useFloat)
  77. {
  78. bool verifyFloat = false;
  79. ret = audio->GetOutputPropertiesEx(&sample_rate, reinterpret_cast<unsigned int *>(nch), reinterpret_cast<unsigned int *>(bps), &verifyFloat);
  80. if (ret == MP4_SUCCESS && !verifyFloat)
  81. return false;
  82. }
  83. else
  84. {
  85. ret = audio->GetOutputProperties(&sample_rate, reinterpret_cast<unsigned int *>(nch), reinterpret_cast<unsigned int *>(bps));
  86. }
  87. if (ret == MP4_SUCCESS)
  88. {
  89. MP4Duration duration = MP4GetTrackDuration(mp4, mp4track);
  90. *srate = sample_rate;
  91. frameSize = (*nch) * (*bps / 8);
  92. size_t outputFrameSize;
  93. *size = duration * frameSize;
  94. if (audio->OutputFrameSize(&outputFrameSize) == MP4_SUCCESS)
  95. {
  96. }
  97. else
  98. {
  99. outputFrameSize = 65536; // err on the side of caution
  100. }
  101. decode_buffer = (uint8_t *)malloc(outputFrameSize*frameSize);
  102. ringBuffer.Initialize(outputFrameSize, *bps, *nch, pregap, postgap);
  103. max_sample_size = MP4GetTrackMaxSampleSize(mp4, mp4track);
  104. sample_buffer = malloc(max_sample_size);
  105. if (sample != 1) {
  106. audio->Flush();
  107. }
  108. return true;
  109. }
  110. unsigned char *buffer = NULL;
  111. unsigned __int32 buffer_size = 0;
  112. if (MP4ReadSample(mp4, mp4track, sample, (unsigned __int8 **)&buffer, &buffer_size))
  113. {
  114. unsigned char tempBuf[65536];
  115. size_t outSize = 65536;
  116. int err = audio->DecodeSample(buffer, buffer_size, tempBuf, &outSize);
  117. MP4Free(buffer);
  118. if (err != MP4_SUCCESS)
  119. continue;
  120. }
  121. }
  122. return false;
  123. }
  124. extern "C"
  125. {
  126. //returns handle!=0 if successful, 0 if error
  127. //size will return the final nb of bytes written to the output, -1 if unknown
  128. __declspec( dllexport ) intptr_t winampGetExtendedRead_openW(const wchar_t *fn, int *size, int *bps, int *nch, int *srate)
  129. {
  130. ExtendedRead *ext = new ExtendedRead;
  131. if (ext->Open(fn, size, bps, nch, srate, false))
  132. return reinterpret_cast<intptr_t>(ext);
  133. delete ext;
  134. return 0;
  135. }
  136. //returns handle!=0 if successful, 0 if error
  137. //size will return the final nb of bytes written to the output, -1 if unknown
  138. __declspec( dllexport ) intptr_t winampGetExtendedRead_openW_float(const wchar_t *fn, int *size, int *bps, int *nch, int *srate)
  139. {
  140. ExtendedRead *ext = new ExtendedRead;
  141. if (ext->Open(fn, size, bps, nch, srate, true))
  142. return reinterpret_cast<intptr_t>(ext);
  143. delete ext;
  144. return 0;
  145. }
  146. //returns nb of bytes read. -1 if read error (like CD ejected). if (ret == 0), EOF is assumed
  147. __declspec( dllexport ) intptr_t winampGetExtendedRead_getData(intptr_t handle, char *dest, int len, volatile int *killswitch)
  148. {
  149. ExtendedRead *ext = (ExtendedRead *)handle;
  150. int bytesCopied = 0;
  151. int skip = 0;
  152. len -= (len % ext->frameSize); // round down to the nearest whole frame size
  153. while (len && !*killswitch)
  154. {
  155. size_t copySize = ext->ringBuffer.Read(dest, len);
  156. len -= copySize;
  157. dest += copySize;
  158. bytesCopied += copySize;
  159. if (ext->ringBuffer.Empty())
  160. {
  161. size_t outSize = 0;
  162. MP4Duration offset=0,duration=INT_MAX;
  163. if (ext->sampleId <= ext->samples) {
  164. unsigned char *buffer = (unsigned char *)ext->sample_buffer;
  165. unsigned __int32 buffer_size = ext->max_sample_size;
  166. MP4ReadSample(ext->mp4, ext->mp4track, ext->sampleId++, (unsigned __int8 **) & buffer, &buffer_size, 0, &duration, &offset);
  167. ext->audio->DecodeSample(buffer, buffer_size, ext->decode_buffer, &outSize); // TODO error check
  168. } else {
  169. #if 0 // TODO Drain decode
  170. ext->audio->DecodeSample(0, 0, decode_buffer, &outSize); // TODO Drain method?
  171. #else
  172. #endif
  173. return bytesCopied;
  174. }
  175. // convert to the track timescale for purposes of duration/offset/gap stuff
  176. int outSamples = MulDiv(outSize, ext->timescale, ext->sample_rate * ext->frameSize);
  177. if (offset > 0)
  178. outSamples -= min(outSamples, offset);
  179. if (outSamples > duration)
  180. outSamples = duration;
  181. // convert back to sample rate timescale
  182. outSize = MulDiv(ext->sample_rate * ext->frameSize, outSamples, ext->timescale);
  183. ext->ringBuffer.Write(ext->decode_buffer+offset*ext->frameSize, outSize);
  184. }
  185. }
  186. return bytesCopied;
  187. }
  188. // return nonzero on success, zero on failure.
  189. __declspec( dllexport ) int winampGetExtendedRead_setTime(intptr_t handle, int millisecs)
  190. {
  191. ExtendedRead *ext = (ExtendedRead *)handle;
  192. MP4Duration duration = MP4ConvertToTrackDuration(ext->mp4, ext->mp4track, millisecs, MP4_MSECS_TIME_SCALE);
  193. if(duration == MP4_INVALID_DURATION) return 0;
  194. MP4SampleId newSampleId = MP4GetSampleIdFromTime(ext->mp4, ext->mp4track, duration);
  195. if(newSampleId > ext->samples) return 0;
  196. ext->sampleId = newSampleId;
  197. ext->audio->Flush();
  198. // ext->bufferUsed=0;
  199. ext->ringBuffer.Reset();
  200. return 1;
  201. }
  202. __declspec( dllexport ) void winampGetExtendedRead_close(intptr_t handle)
  203. {
  204. ExtendedRead *ext = (ExtendedRead *)handle;
  205. delete ext;
  206. }
  207. }