xref: /haiku/src/kits/media/MediaFile.cpp (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
1 /*
2  * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
3  * Copyright 2002-2004, Marcus Overhagen <marcus@overhagen.de>
4  * All rights reserved. Distributed under the terms of the MIT license.
5  */
6 
7 #include <MediaFile.h>
8 
9 #include <new>
10 
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <BufferIO.h>
15 #include <File.h>
16 #include <MediaTrack.h>
17 
18 #include "debug.h"
19 
20 #include "MediaExtractor.h"
21 #include "MediaWriter.h"
22 
23 
24 BMediaFile::BMediaFile(const entry_ref* ref)
25 {
26 	CALLED();
27 	_Init();
28 	fDeleteSource = true;
29 	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY));
30 }
31 
32 
33 BMediaFile::BMediaFile(BDataIO* source)
34 {
35 	CALLED();
36 	_Init();
37 	_InitReader(source);
38 }
39 
40 
41 BMediaFile::BMediaFile(const entry_ref* ref, int32 flags)
42 {
43 	CALLED();
44 	_Init();
45 	fDeleteSource = true;
46 	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY), flags);
47 }
48 
49 
50 BMediaFile::BMediaFile(BDataIO* source, int32 flags)
51 {
52 	CALLED();
53 	_Init();
54 	_InitReader(source, flags);
55 }
56 
57 
58 BMediaFile::BMediaFile(const entry_ref* ref, const media_file_format* mfi,
59 	int32 flags)
60 {
61 	CALLED();
62 	_Init();
63 	fDeleteSource = true;
64 	_InitWriter(new(std::nothrow) BFile(ref, B_CREATE_FILE | B_ERASE_FILE
65 		| B_WRITE_ONLY), mfi, flags);
66 }
67 
68 
69 BMediaFile::BMediaFile(BDataIO* destination, const media_file_format* mfi,
70 	int32 flags)
71 {
72 	CALLED();
73 	_Init();
74 	_InitWriter(destination, mfi, flags);
75 }
76 
77 
78 // File will be set later by SetTo()
79 BMediaFile::BMediaFile(const media_file_format* mfi, int32 flags)
80 {
81 	debugger("BMediaFile::BMediaFile not implemented");
82 }
83 
84 
85 status_t
86 BMediaFile::SetTo(const entry_ref* ref)
87 {
88 	CALLED();
89 
90 	if (ref == NULL)
91 		return B_BAD_VALUE;
92 
93 	_UnInit();
94 	fDeleteSource = true;
95 	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY));
96 
97 	return fErr;
98 }
99 
100 
101 status_t
102 BMediaFile::SetTo(BDataIO* destination)
103 {
104 	CALLED();
105 
106 	if (destination == NULL)
107 		return B_BAD_VALUE;
108 
109 	_UnInit();
110 	_InitReader(destination);
111 
112 	return fErr;
113 }
114 
115 
116 BMediaFile::~BMediaFile()
117 {
118 	CALLED();
119 
120 	_UnInit();
121 }
122 
123 
124 status_t
125 BMediaFile::InitCheck() const
126 {
127 	CALLED();
128 	return fErr;
129 }
130 
131 
132 // Get info about the underlying file format.
133 status_t
134 BMediaFile::GetFileFormatInfo(media_file_format* mfi) const
135 {
136 	CALLED();
137 	if (mfi == NULL)
138 		return B_BAD_VALUE;
139 	if (fErr)
140 		return B_ERROR;
141 	*mfi = fMFI;
142 	return B_OK;
143 }
144 
145 
146 const char*
147 BMediaFile::Copyright() const
148 {
149 	return fExtractor->Copyright();
150 }
151 
152 
153 int32
154 BMediaFile::CountTracks() const
155 {
156 	return fTrackNum;
157 }
158 
159 
160 // Can be called multiple times with the same index.  You must call
161 // ReleaseTrack() when you're done with a track.
162 BMediaTrack*
163 BMediaFile::TrackAt(int32 index)
164 {
165 	CALLED();
166 	if (fTrackList == NULL || fExtractor == NULL
167 		|| index < 0 || index >= fTrackNum) {
168 		return NULL;
169 	}
170 	if (fTrackList[index] == NULL) {
171 		TRACE("BMediaFile::TrackAt, creating new track for index %ld\n", index);
172 		fTrackList[index] = new(std::nothrow) BMediaTrack(fExtractor, index);
173 		TRACE("BMediaFile::TrackAt, new track is %p\n", fTrackList[index]);
174 	}
175 	return fTrackList[index];
176 }
177 
178 
179 // Release the resource used by a given BMediaTrack object, to reduce
180 // the memory usage of your application. The specific 'track' object
181 // can no longer be used, but you can create another one by calling
182 // TrackAt() with the same track index.
183 status_t
184 BMediaFile::ReleaseTrack(BMediaTrack* track)
185 {
186 	CALLED();
187 	if (!fTrackList || !track)
188 		return B_ERROR;
189 	for (int32 i = 0; i < fTrackNum; i++) {
190 		if (fTrackList[i] == track) {
191 			TRACE("BMediaFile::ReleaseTrack, releasing track %p with index "
192 				"%ld\n", track, i);
193 			delete track;
194 			fTrackList[i] = NULL;
195 			return B_OK;
196 		}
197 	}
198 	fprintf(stderr, "BMediaFile::ReleaseTrack track %p not found\n", track);
199 	return B_ERROR;
200 }
201 
202 
203 status_t
204 BMediaFile::ReleaseAllTracks()
205 {
206 	CALLED();
207 	if (!fTrackList)
208 		return B_ERROR;
209 	for (int32 i = 0; i < fTrackNum; i++) {
210 		if (fTrackList[i]) {
211 			TRACE("BMediaFile::ReleaseAllTracks, releasing track %p with "
212 				"index %ld\n", fTrackList[i], i);
213 			delete fTrackList[i];
214 			fTrackList[i] = NULL;
215 		}
216 	}
217 	return B_OK;
218 }
219 
220 
221 // Create and add a track to the media file
222 BMediaTrack*
223 BMediaFile::CreateTrack(media_format* mediaFormat,
224 	const media_codec_info* codecInfo, uint32 flags)
225 {
226 	if (mediaFormat == NULL)
227 		return NULL;
228 
229 	// NOTE: It is allowed to pass NULL for codecInfo. In that case, the
230 	// track won't have an Encoder and you can only use WriteChunk() with
231 	// already encoded data.
232 
233 	// Make room for the new track.
234 	BMediaTrack** trackList = (BMediaTrack**)realloc(fTrackList,
235 		(fTrackNum + 1) * sizeof(BMediaTrack*));
236 	if (trackList == NULL)
237 		return NULL;
238 
239 	int32 streamIndex = fTrackNum;
240 	fTrackList = trackList;
241 	fTrackNum += 1;
242 
243 	BMediaTrack* track = new(std::nothrow) BMediaTrack(fWriter, streamIndex,
244 		mediaFormat, codecInfo);
245 
246 	fTrackList[streamIndex] = track;
247 
248 	return track;
249 }
250 
251 
252 // Create and add a raw track to the media file (it has no encoder)
253 BMediaTrack*
254 BMediaFile::CreateTrack(media_format* mf, uint32 flags)
255 {
256 	return CreateTrack(mf, NULL, flags);
257 }
258 
259 
260 // For BeOS R5 compatibility
261 extern "C" BMediaTrack*
262 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(
263 	BMediaFile* self, media_format* mf, const media_codec_info* mci);
264 BMediaTrack*
265 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(BMediaFile* self,
266 	media_format* mf, const media_codec_info* mci)
267 {
268 	return self->CreateTrack(mf, mci, 0);
269 }
270 
271 
272 // For BeOS R5 compatibility
273 extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format(
274 	BMediaFile* self, media_format* mf);
275 BMediaTrack*
276 CreateTrack__10BMediaFileP12media_format(BMediaFile* self, media_format* mf)
277 {
278 	return self->CreateTrack(mf, NULL, 0);
279 }
280 
281 
282 // Lets you set the copyright info for the entire file
283 status_t
284 BMediaFile::AddCopyright(const char* copyright)
285 {
286 	if (fWriter == NULL)
287 		return B_NO_INIT;
288 
289 	return fWriter->SetCopyright(copyright);
290 }
291 
292 
293 // Call this to add user-defined chunks to a file (if they're supported)
294 status_t
295 BMediaFile::AddChunk(int32 type, const void* data, size_t size)
296 {
297 	UNIMPLEMENTED();
298 	return B_OK;
299 }
300 
301 
302 // After you have added all the tracks you want, call this
303 status_t
304 BMediaFile::CommitHeader()
305 {
306 	if (fWriter == NULL)
307 		return B_NO_INIT;
308 
309 	return fWriter->CommitHeader();
310 }
311 
312 
313 // After you have written all the data to the track objects, call this
314 status_t
315 BMediaFile::CloseFile()
316 {
317 	if (fWriter == NULL)
318 		return B_NO_INIT;
319 
320 	return fWriter->Close();
321 }
322 
323 // This is for controlling file format parameters
324 
325 // returns a copy of the parameter web
326 status_t
327 BMediaFile::GetParameterWeb(BParameterWeb** outWeb)
328 {
329 	UNIMPLEMENTED();
330 	return B_ERROR;
331 }
332 
333 
334 // deprecated BeOS R5 API
335 BParameterWeb*
336 BMediaFile::Web()
337 {
338 	UNIMPLEMENTED();
339 	return 0;
340 }
341 
342 
343 status_t
344 BMediaFile::GetParameterValue(int32 id,	void* value, size_t* size)
345 {
346 	UNIMPLEMENTED();
347 	return B_OK;
348 }
349 
350 
351 status_t
352 BMediaFile::SetParameterValue(int32 id,	const void* value, size_t size)
353 {
354 	UNIMPLEMENTED();
355 	return B_OK;
356 }
357 
358 
359 BView*
360 BMediaFile::GetParameterView()
361 {
362 	UNIMPLEMENTED();
363 	return 0;
364 }
365 
366 
367 status_t
368 BMediaFile::Perform(int32 selector, void* data)
369 {
370 	UNIMPLEMENTED();
371 	return B_OK;
372 }
373 
374 
375 status_t
376 BMediaFile::ControlFile(int32 selector, void* ioData, size_t size)
377 {
378 	UNIMPLEMENTED();
379 	return B_ERROR;
380 }
381 
382 
383 // #pragma mark - private
384 
385 
386 void
387 BMediaFile::_Init()
388 {
389 	CALLED();
390 
391 	fSource = NULL;
392 	fTrackNum = 0;
393 	fTrackList = NULL;
394 	fExtractor = NULL;
395 	fWriter = NULL;
396 	fWriterID = 0;
397 	fErr = B_OK;
398 	fDeleteSource = false;
399 
400 	// not used so far:
401 	fEncoderMgr = NULL;
402 	fWriterMgr = NULL;
403 	fFileClosed = false;
404 }
405 
406 
407 void
408 BMediaFile::_UnInit()
409 {
410 	ReleaseAllTracks();
411 	free(fTrackList);
412 	fTrackList = NULL;
413 	fTrackNum = 0;
414 	delete fExtractor;
415 	fExtractor = NULL;
416 	delete fWriter;
417 	fWriter = NULL;
418 	if (fDeleteSource) {
419 		delete fSource;
420 		fSource = NULL;
421 		fDeleteSource = false;
422 	}
423 }
424 
425 
426 void
427 BMediaFile::_InitReader(BDataIO* source, int32 flags)
428 {
429 	CALLED();
430 
431 	if (source == NULL) {
432 		fErr = B_NO_MEMORY;
433 		return;
434 	}
435 
436 	if (dynamic_cast<BBufferIO *>(source)) {
437 		// Already buffered
438 		fSource = source;
439 	} else {
440 		// Source needs to be at least a BPositionIO to wrap with a BBufferIO
441 		if (dynamic_cast<BPositionIO *>(source)) {
442 			fSource = new(std::nothrow) BBufferIO(dynamic_cast<BPositionIO *>(source), 65536, fDeleteSource);
443 			if (fSource == NULL) {
444 				fErr = B_NO_MEMORY;
445 				return;
446 			}
447 			fDeleteSource = true;
448 		} else {
449 			TRACE("Unable to improve performance with a BufferIO\n");
450 			fSource = source;
451 		}
452 	}
453 
454 	fExtractor = new(std::nothrow) MediaExtractor(fSource, flags);
455 	if (fExtractor == NULL)
456 		fErr = B_NO_MEMORY;
457 	else
458 		fErr = fExtractor->InitCheck();
459 	if (fErr != B_OK)
460 		return;
461 
462 	fExtractor->GetFileFormatInfo(&fMFI);
463 	fTrackNum = fExtractor->StreamCount();
464 	fTrackList = (BMediaTrack**)malloc(fTrackNum * sizeof(BMediaTrack*));
465 	if (fTrackList == NULL) {
466 		fErr = B_NO_MEMORY;
467 		return;
468 	}
469 	memset(fTrackList, 0, fTrackNum * sizeof(BMediaTrack*));
470 }
471 
472 
473 void
474 BMediaFile::_InitWriter(BDataIO* target, const media_file_format* fileFormat,
475 	int32 flags)
476 {
477 	CALLED();
478 
479 	if (fileFormat == NULL) {
480 		fErr = B_BAD_VALUE;
481 		return;
482 	}
483 
484 	if (target == NULL) {
485 		fErr = B_NO_MEMORY;
486 		return;
487 	}
488 
489 	fMFI = *fileFormat;
490 	fSource = target;
491 
492 	fWriter = new(std::nothrow) MediaWriter(fSource, fMFI);
493 	if (fWriter == NULL)
494 		fErr = B_NO_MEMORY;
495 	else
496 		fErr = fWriter->InitCheck();
497 	if (fErr != B_OK)
498 		return;
499 
500 	fTrackNum = 0;
501 }
502 
503 
504 /*
505 //unimplemented
506 BMediaFile::BMediaFile();
507 BMediaFile::BMediaFile(const BMediaFile&);
508  BMediaFile::BMediaFile& operator=(const BMediaFile&);
509 */
510 
511 status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; }
512 status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; }
513 status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; }
514 status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; }
515 status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; }
516 status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; }
517 status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; }
518 status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; }
519 status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; }
520 status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; }
521 status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; }
522 status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; }
523 status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; }
524 status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; }
525 status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; }
526 status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; }
527 status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; }
528 status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; }
529 status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; }
530 status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; }
531 status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; }
532 status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; }
533 status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; }
534 status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; }
535 status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; }
536 status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; }
537 status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; }
538 status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; }
539 status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; }
540 status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; }
541 status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; }
542 status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; }
543 status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; }
544 status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; }
545 status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; }
546 status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; }
547 status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; }
548 status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; }
549 status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; }
550 status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; }
551 status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; }
552 status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; }
553 status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; }
554 status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; }
555 status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; }
556 status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; }
557 status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; }
558 status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; }
559 
560