xref: /haiku/src/kits/media/MediaExtractor.cpp (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 #include "MediaExtractor.h"
2 #include "PluginManager.h"
3 #include "debug.h"
4 
5 #include <Autolock.h>
6 
7 #include <stdio.h>
8 #include <string.h>
9 
10 
11 MediaExtractor::MediaExtractor(BDataIO *source, int32 flags)
12 {
13 	CALLED();
14 	fSource = source;
15 	fStreamInfo = 0;
16 
17 	fErr = _CreateReader(&fReader, &fStreamCount, &fMff, source);
18 	if (fErr) {
19 		fStreamCount = 0;
20 		fReader = 0;
21 		return;
22 	}
23 
24 	fStreamInfo = new stream_info[fStreamCount];
25 
26 	// initialize stream infos
27 	for (int32 i = 0; i < fStreamCount; i++) {
28 		fStreamInfo[i].status = B_OK;
29 		fStreamInfo[i].cookie = 0;
30 		fStreamInfo[i].hasCookie = true;
31 		fStreamInfo[i].infoBuffer = 0;
32 		fStreamInfo[i].infoBufferSize = 0;
33 		memset(&fStreamInfo[i].encodedFormat, 0, sizeof(fStreamInfo[i].encodedFormat));
34 	}
35 
36 	// create all stream cookies
37 	for (int32 i = 0; i < fStreamCount; i++) {
38 		if (B_OK != fReader->AllocateCookie(i, &fStreamInfo[i].cookie)) {
39 			fStreamInfo[i].cookie = 0;
40 			fStreamInfo[i].hasCookie = false;
41 			fStreamInfo[i].status = B_ERROR;
42 			printf("MediaExtractor::MediaExtractor: AllocateCookie for stream %ld failed\n", i);
43 		}
44 	}
45 
46 	// get info for all streams
47 	for (int32 i = 0; i < fStreamCount; i++) {
48 		if (fStreamInfo[i].status != B_OK)
49 			continue;
50 		int64 frameCount;
51 		bigtime_t duration;
52 		if (B_OK != fReader->GetStreamInfo(fStreamInfo[i].cookie, &frameCount, &duration,
53 										   &fStreamInfo[i].encodedFormat,
54 										   &fStreamInfo[i].infoBuffer,
55 										   &fStreamInfo[i].infoBufferSize)) {
56 			fStreamInfo[i].status = B_ERROR;
57 			printf("MediaExtractor::MediaExtractor: GetStreamInfo for stream %ld failed\n", i);
58 		}
59 	}
60 }
61 
62 MediaExtractor::~MediaExtractor()
63 {
64 	CALLED();
65 
66 	// free all stream cookies
67 	for (int32 i = 0; i < fStreamCount; i++) {
68 		if (fStreamInfo[i].hasCookie)
69 			fReader->FreeCookie(fStreamInfo[i].cookie);
70 	}
71 
72 	if (fReader)
73 		_DestroyReader(fReader);
74 
75 	delete [] fStreamInfo;
76 	// fSource is owned by the BMediaFile
77 }
78 
79 status_t
80 MediaExtractor::InitCheck()
81 {
82 	CALLED();
83 	return fErr;
84 }
85 
86 void
87 MediaExtractor::GetFileFormatInfo(media_file_format *mfi) const
88 {
89 	CALLED();
90 	*mfi = fMff;
91 }
92 
93 int32
94 MediaExtractor::StreamCount()
95 {
96 	CALLED();
97 	return fStreamCount;
98 }
99 
100 const media_format *
101 MediaExtractor::EncodedFormat(int32 stream)
102 {
103 	return &fStreamInfo[stream].encodedFormat;
104 }
105 
106 int64
107 MediaExtractor::CountFrames(int32 stream) const
108 {
109 	CALLED();
110 	int64 frameCount;
111 	bigtime_t duration;
112 	media_format format;
113 	void *infoBuffer;
114 	int32 infoSize;
115 
116 	fReader->GetStreamInfo(fStreamInfo[stream].cookie, &frameCount, &duration, &format, &infoBuffer, &infoSize);
117 
118 	return frameCount;
119 }
120 
121 bigtime_t
122 MediaExtractor::Duration(int32 stream) const
123 {
124 	CALLED();
125 	int64 frameCount;
126 	bigtime_t duration;
127 	media_format format;
128 	void *infoBuffer;
129 	int32 infoSize;
130 
131 	fReader->GetStreamInfo(fStreamInfo[stream].cookie, &frameCount, &duration, &format, &infoBuffer, &infoSize);
132 
133 	return duration;
134 }
135 
136 status_t
137 MediaExtractor::Seek(int32 stream, uint32 seekTo,
138 					 int64 *frame, bigtime_t *time)
139 {
140 	CALLED();
141 	status_t result;
142 	result = fReader->Seek(fStreamInfo[stream].cookie, seekTo, frame, time);
143 	if (result != B_OK)
144 		return result;
145 
146 	// clear buffered chunks
147 	return B_OK;
148 }
149 
150 status_t
151 MediaExtractor::GetNextChunk(int32 stream,
152 							 void **chunkBuffer, int32 *chunkSize,
153 							 media_header *mediaHeader)
154 {
155 	//CALLED();
156 	// get buffered chunk
157 
158 	// XXX until this is done in a single extractor thread,
159 	// XXX make calls to GetNextChunk thread save
160 	static BLocker locker;
161 	BAutolock lock(locker);
162 
163 	// XXX this should be done in a different thread, and double buffered for each stream
164 	return fReader->GetNextChunk(fStreamInfo[stream].cookie, chunkBuffer, chunkSize, mediaHeader);
165 }
166 
167 class MediaExtractorChunkProvider : public ChunkProvider {
168 private:
169 	MediaExtractor * fExtractor;
170 	int32 fStream;
171 public:
172 	MediaExtractorChunkProvider(MediaExtractor * extractor, int32 stream) {
173 		fExtractor = extractor;
174 		fStream = stream;
175 	}
176 	virtual status_t GetNextChunk(void **chunkBuffer, int32 *chunkSize,
177 	                              media_header *mediaHeader) {
178 		return fExtractor->GetNextChunk(fStream,chunkBuffer,chunkSize,mediaHeader);
179 	}
180 };
181 
182 status_t
183 MediaExtractor::CreateDecoder(int32 stream, Decoder **decoder, media_codec_info *mci)
184 {
185 	CALLED();
186 	status_t res;
187 
188 	res = fStreamInfo[stream].status;
189 	if (res != B_OK) {
190 		printf("MediaExtractor::CreateDecoder can't create decoder for stream %ld\n", stream);
191 		return res;
192 	}
193 
194 	res = _CreateDecoder(decoder, fStreamInfo[stream].encodedFormat);
195 	if (res != B_OK) {
196 		printf("MediaExtractor::CreateDecoder failed for stream %ld\n", stream);
197 		return res;
198 	}
199 
200 	(*decoder)->Setup(new MediaExtractorChunkProvider(this, stream));
201 
202 	res = (*decoder)->Setup(&fStreamInfo[stream].encodedFormat, fStreamInfo[stream].infoBuffer , fStreamInfo[stream].infoBufferSize);
203 	if (res != B_OK) {
204 		printf("MediaExtractor::CreateDecoder Setup failed for stream %ld: %ld (%s)\n",
205 			stream, res, strerror(res));
206 		return res;
207 	}
208 
209 	(*decoder)->GetCodecInfo(mci);
210 
211 	return B_OK;
212 }
213 
214