1
1
#pragma once
2
+ #include < new>
2
3
#include " AudioTools/AudioCodecs/AudioCodecsBase.h"
3
4
#include " AudioTools/CoreAudio/AudioBasic/StrView.h"
4
5
#include " AudioTools/CoreAudio/AudioMetaData/MimeDetector.h"
7
8
8
9
namespace audio_tools {
9
10
11
+ /* *
12
+ * @brief Stream that combines prefix data with original stream
13
+ *
14
+ * Useful for format detection where some data needs to be preserved.
15
+ *
16
+ * @ingroup io
17
+ * @author Phil Schatzmann
18
+ * @copyright GPLv3
19
+ */
20
+ class PrefixStream : public Stream {
21
+ public:
22
+ // / Default constructor - call setData() before use
23
+ PrefixStream ()
24
+ : prefix_data_(nullptr ), prefix_len_(0 ), prefix_pos_(0 ), original_stream_(nullptr ) {}
25
+
26
+ // / Constructor with prefix data and original stream
27
+ PrefixStream (const uint8_t * prefix_data, size_t prefix_len, Stream& original_stream)
28
+ : prefix_data_(prefix_data), prefix_len_(prefix_len), prefix_pos_(0 ), original_stream_(&original_stream) {}
29
+
30
+ // / Sets the prefix data and original stream
31
+ void setData (const uint8_t * prefix_data, size_t prefix_len, Stream& original_stream) {
32
+ prefix_data_ = prefix_data;
33
+ prefix_len_ = prefix_len;
34
+ prefix_pos_ = 0 ;
35
+ original_stream_ = &original_stream;
36
+ }
37
+
38
+ // / Returns total bytes available (prefix + original stream)
39
+ virtual int available () override {
40
+ int remaining_prefix = prefix_len_ - prefix_pos_;
41
+ if (original_stream_ != nullptr ) {
42
+ return remaining_prefix + original_stream_->available ();
43
+ }
44
+ return remaining_prefix;
45
+ }
46
+
47
+ // / Reads a single byte
48
+ virtual int read () override {
49
+ if (prefix_pos_ < prefix_len_) {
50
+ return prefix_data_[prefix_pos_++];
51
+ }
52
+ if (original_stream_ != nullptr ) {
53
+ return original_stream_->read ();
54
+ }
55
+ return -1 ;
56
+ }
57
+
58
+ // / Peeks at next byte without consuming it
59
+ virtual int peek () override {
60
+ if (prefix_pos_ < prefix_len_) {
61
+ return prefix_data_[prefix_pos_];
62
+ }
63
+ if (original_stream_ != nullptr ) {
64
+ return original_stream_->peek ();
65
+ }
66
+ return -1 ;
67
+ }
68
+
69
+ // / Reads multiple bytes into buffer
70
+ virtual size_t readBytes (uint8_t * buffer, size_t length) override {
71
+ size_t bytes_read = 0 ;
72
+
73
+ // First, read from prefix data
74
+ if (prefix_pos_ < prefix_len_) {
75
+ size_t prefix_available = prefix_len_ - prefix_pos_;
76
+ size_t prefix_to_read = (length < prefix_available) ? length : prefix_available;
77
+ memcpy (buffer, prefix_data_ + prefix_pos_, prefix_to_read);
78
+ prefix_pos_ += prefix_to_read;
79
+ bytes_read += prefix_to_read;
80
+ buffer += prefix_to_read;
81
+ length -= prefix_to_read;
82
+ }
83
+
84
+ // Then read from original stream if more data is needed
85
+ if (length > 0 && original_stream_ != nullptr ) {
86
+ bytes_read += original_stream_->readBytes (buffer, length);
87
+ }
88
+
89
+ return bytes_read;
90
+ }
91
+
92
+ // / Write operations not supported
93
+ virtual size_t write (uint8_t ) override { return 0 ; }
94
+ virtual size_t write (const uint8_t *, size_t ) override { return 0 ; }
95
+ virtual void flush () override {}
96
+
97
+ private:
98
+ const uint8_t * prefix_data_; // /< Prefix data buffer
99
+ size_t prefix_len_; // /< Length of prefix data
100
+ size_t prefix_pos_; // /< Current position in prefix
101
+ Stream* original_stream_; // /< Original stream
102
+ };
103
+
10
104
/* *
11
105
* @brief A Streaming Decoder where we provide both the input and output
12
106
* as streams.
@@ -343,7 +437,7 @@ class MultiStreamingDecoder : public StreamingDecoder {
343
437
for (auto * adapter : adapters) {
344
438
delete adapter;
345
439
}
346
- adapters.clear ();
440
+ adapters.clear ();
347
441
}
348
442
349
443
/* *
@@ -376,7 +470,7 @@ class MultiStreamingDecoder : public StreamingDecoder {
376
470
actual_decoder.is_open = false ;
377
471
actual_decoder.decoder = nullptr ;
378
472
actual_decoder.mime = nullptr ;
379
- is_first = true ;
473
+ is_first = true ;
380
474
}
381
475
382
476
/* *
@@ -720,14 +814,15 @@ class MultiStreamingDecoder : public StreamingDecoder {
720
814
Vector<StreamingDecoderAdapter*> adapters{
721
815
0 }; // /< Collection of internally created adapters
722
816
MimeDetector mime_detector; // /< MIME type detection engine
723
- BufferedStream buffered_stream{0 }; // /< Buffered stream for data preservation
724
817
Vector<uint8_t > detection_buffer{0 }; // /< Buffer for format detection data
725
818
bool is_first = true ; // /< Flag for first copy() call
726
819
const char * selected_mime = nullptr ; // /< MIME type that was selected
727
820
MimeSource* p_mime_source =
728
821
nullptr ; // /< Optional MIME source for custom logic
729
822
Stream *p_data_source = nullptr ; // /< effective data source for decoder
730
823
824
+ PrefixStream prefix_stream; // /< Instance of prefix stream (uses placement new on prefix_stream_storage)
825
+
731
826
const char * toStr (const char * str){
732
827
return str == nullptr ? " " : str;
733
828
}
@@ -777,19 +872,13 @@ class MultiStreamingDecoder : public StreamingDecoder {
777
872
p_data_source = p_input;
778
873
} else {
779
874
// Option 2: Auto-detect MIME type by analyzing stream content
780
- // Redirect the decoder to use the buffered stream
781
- // we use the buffered stream as input
782
875
assert (p_input != nullptr );
783
- buffered_stream.setStream (*p_input);
784
- buffered_stream.resize (DEFAULT_BUFFER_SIZE);
785
- p_data_source = &buffered_stream;
786
876
787
- // This requires reading a sample of data to identify the format
788
-
789
- // Allocate buffer for MIME detection sample (80 bytes is typically sufficient
877
+ // Read a sample of data for MIME detection
878
+ // Allocate buffer for MIME detection sample (160 bytes is sufficient
790
879
// for most audio format headers to be identified)
791
880
detection_buffer.resize (160 );
792
- size_t bytesRead = buffered_stream. peekBytes (detection_buffer.data (), detection_buffer.size ());
881
+ size_t bytesRead = p_input-> readBytes (detection_buffer.data (), detection_buffer.size ());
793
882
794
883
// If no data is available, we cannot proceed with detection
795
884
if (bytesRead == 0 ) return false ;
@@ -799,6 +888,11 @@ class MultiStreamingDecoder : public StreamingDecoder {
799
888
mime_detector.write (detection_buffer.data (), bytesRead);
800
889
mime = mime_detector.mime ();
801
890
LOGI (" mime from detector: %s" , toStr (mime));
891
+
892
+ // Create a prefix stream that combines the detection data with the original stream
893
+ // This ensures the decoder receives the complete stream including the bytes used for detection
894
+ prefix_stream.setData (detection_buffer.data (), bytesRead, *p_input);
895
+ p_data_source = &prefix_stream;
802
896
}
803
897
804
898
// Process the detected/provided MIME type
0 commit comments