xref: /haiku/src/kits/media/MediaFile.cpp (revision df4074fbed092b09474695aa286752ca41625332)
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 <File.h>
15 #include <MediaTrack.h>
16 #include <Url.h>
17 
18 #include "MediaDebug.h"
19 
20 #include "MediaExtractor.h"
21 #include "MediaStreamer.h"
22 #include "MediaWriter.h"
23 
24 
25 BMediaFile::BMediaFile(const entry_ref* ref)
26 {
27 	CALLED();
28 	_Init();
29 	fDeleteSource = true;
30 	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY));
31 }
32 
33 
34 BMediaFile::BMediaFile(BDataIO* source)
35 {
36 	CALLED();
37 	_Init();
38 	_InitReader(source);
39 }
40 
41 
42 BMediaFile::BMediaFile(const entry_ref* ref, int32 flags)
43 {
44 	CALLED();
45 	_Init();
46 	fDeleteSource = true;
47 	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY), NULL, flags);
48 }
49 
50 
51 BMediaFile::BMediaFile(BDataIO* source, int32 flags)
52 {
53 	CALLED();
54 	_Init();
55 	_InitReader(source, NULL, flags);
56 }
57 
58 
59 BMediaFile::BMediaFile(const entry_ref* ref, const media_file_format* mfi,
60 	int32 flags)
61 {
62 	CALLED();
63 	_Init();
64 	fDeleteSource = true;
65 	_InitWriter(new(std::nothrow) BFile(ref, B_CREATE_FILE | B_ERASE_FILE
66 		| B_WRITE_ONLY), NULL, mfi, flags);
67 }
68 
69 
70 BMediaFile::BMediaFile(BDataIO* destination, const media_file_format* mfi,
71 	int32 flags)
72 {
73 	CALLED();
74 	_Init();
75 	_InitWriter(destination, NULL, mfi, flags);
76 }
77 
78 
79 // File will be set later by SetTo()
80 BMediaFile::BMediaFile(const media_file_format* mfi, int32 flags)
81 {
82 	debugger("BMediaFile::BMediaFile not implemented");
83 }
84 
85 
86 BMediaFile::BMediaFile(const BUrl& url)
87 {
88 	CALLED();
89 	_Init();
90 	fDeleteSource = true;
91 	_InitReader(NULL, &url);
92 }
93 
94 
95 BMediaFile::BMediaFile(const BUrl& url, int32 flags)
96 {
97 	CALLED();
98 	_Init();
99 	fDeleteSource = true;
100 	_InitReader(NULL, &url, flags);
101 }
102 
103 
104 BMediaFile::BMediaFile(const BUrl& destination, const media_file_format* mfi,
105 	int32 flags)
106 {
107 	CALLED();
108 	_Init();
109 	fDeleteSource = true;
110 	_InitWriter(NULL, &destination, mfi, flags);
111 	// TODO: Implement streaming server support, it's
112 	// a pretty complex thing compared to client mode
113 	// and will require to expand the current BMediaFile
114 	// design to be aware of it.
115 }
116 
117 
118 status_t
119 BMediaFile::SetTo(const entry_ref* ref)
120 {
121 	CALLED();
122 
123 	if (ref == NULL)
124 		return B_BAD_VALUE;
125 
126 	_UnInit();
127 	fDeleteSource = true;
128 	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY));
129 
130 	return fErr;
131 }
132 
133 
134 status_t
135 BMediaFile::SetTo(BDataIO* destination)
136 {
137 	CALLED();
138 
139 	if (destination == NULL)
140 		return B_BAD_VALUE;
141 
142 	_UnInit();
143 	_InitReader(destination);
144 
145 	return fErr;
146 }
147 
148 
149 status_t
150 BMediaFile::SetTo(const BUrl& url)
151 {
152 	CALLED();
153 
154 	_UnInit();
155 	_InitReader(NULL, &url);
156 
157 	return fErr;
158 }
159 
160 
161 BMediaFile::~BMediaFile()
162 {
163 	CALLED();
164 
165 	_UnInit();
166 }
167 
168 
169 status_t
170 BMediaFile::InitCheck() const
171 {
172 	CALLED();
173 	return fErr;
174 }
175 
176 
177 status_t
178 BMediaFile::GetFileFormatInfo(media_file_format* mfi) const
179 {
180 	CALLED();
181 	if (mfi == NULL)
182 		return B_BAD_VALUE;
183 	if (fErr)
184 		return B_ERROR;
185 	*mfi = fMFI;
186 	return B_OK;
187 }
188 
189 
190 status_t
191 BMediaFile::GetMetaData(BMessage* _data) const
192 {
193 	if (fExtractor == NULL)
194 		return B_NO_INIT;
195 	if (_data == NULL)
196 		return B_BAD_VALUE;
197 
198 	_data->MakeEmpty();
199 
200 	BMetaData* metaData = NULL;
201 	if (fExtractor->GetMetaData(metaData) == B_OK) {
202 		*_data = *metaData->Message();
203 		return B_OK;
204 	}
205 
206 	return B_ERROR;
207 }
208 
209 
210 const char*
211 BMediaFile::Copyright() const
212 {
213 	BMetaData data;
214 	BString copyright;
215 	if (fExtractor->GetMetaData(&data) == B_OK)
216 		data.GetString(kCopyright, &copyright);
217 
218 	return copyright.String();
219 }
220 
221 
222 int32
223 BMediaFile::CountTracks() const
224 {
225 	return fTrackNum;
226 }
227 
228 
229 // Can be called multiple times with the same index.  You must call
230 // ReleaseTrack() when you're done with a track.
231 BMediaTrack*
232 BMediaFile::TrackAt(int32 index)
233 {
234 	CALLED();
235 	if (fTrackList == NULL || fExtractor == NULL
236 		|| index < 0 || index >= fTrackNum) {
237 		return NULL;
238 	}
239 	if (fTrackList[index] == NULL) {
240 		TRACE("BMediaFile::TrackAt, creating new track for index %"
241 			B_PRId32 "\n", index);
242 		fTrackList[index] = new(std::nothrow) BMediaTrack(fExtractor, index);
243 		TRACE("BMediaFile::TrackAt, new track is %p\n", fTrackList[index]);
244 	}
245 	return fTrackList[index];
246 }
247 
248 
249 // Release the resource used by a given BMediaTrack object, to reduce
250 // the memory usage of your application. The specific 'track' object
251 // can no longer be used, but you can create another one by calling
252 // TrackAt() with the same track index.
253 status_t
254 BMediaFile::ReleaseTrack(BMediaTrack* track)
255 {
256 	CALLED();
257 	if (!fTrackList || !track)
258 		return B_ERROR;
259 	for (int32 i = 0; i < fTrackNum; i++) {
260 		if (fTrackList[i] == track) {
261 			TRACE("BMediaFile::ReleaseTrack, releasing track %p with index "
262 				"%" B_PRId32 "\n", track, i);
263 			delete track;
264 			fTrackList[i] = NULL;
265 			return B_OK;
266 		}
267 	}
268 	fprintf(stderr, "BMediaFile::ReleaseTrack track %p not found\n", track);
269 	return B_ERROR;
270 }
271 
272 
273 status_t
274 BMediaFile::ReleaseAllTracks()
275 {
276 	CALLED();
277 	if (!fTrackList)
278 		return B_ERROR;
279 	for (int32 i = 0; i < fTrackNum; i++) {
280 		if (fTrackList[i]) {
281 			TRACE("BMediaFile::ReleaseAllTracks, releasing track %p with "
282 				"index %" B_PRId32 "\n", fTrackList[i], i);
283 			delete fTrackList[i];
284 			fTrackList[i] = NULL;
285 		}
286 	}
287 	return B_OK;
288 }
289 
290 
291 // Create and add a track to the media file
292 BMediaTrack*
293 BMediaFile::CreateTrack(media_format* mediaFormat,
294 	const media_codec_info* codecInfo, uint32 flags)
295 {
296 	if (mediaFormat == NULL)
297 		return NULL;
298 
299 	// NOTE: It is allowed to pass NULL for codecInfo. In that case, the
300 	// track won't have an Encoder and you can only use WriteChunk() with
301 	// already encoded data.
302 
303 	// Make room for the new track.
304 	BMediaTrack** trackList = (BMediaTrack**)realloc(fTrackList,
305 		(fTrackNum + 1) * sizeof(BMediaTrack*));
306 	if (trackList == NULL)
307 		return NULL;
308 
309 	int32 streamIndex = fTrackNum;
310 	fTrackList = trackList;
311 	fTrackNum += 1;
312 
313 	BMediaTrack* track = new(std::nothrow) BMediaTrack(fWriter, streamIndex,
314 		mediaFormat, codecInfo);
315 
316 	fTrackList[streamIndex] = track;
317 
318 	return track;
319 }
320 
321 
322 // Create and add a raw track to the media file (it has no encoder)
323 BMediaTrack*
324 BMediaFile::CreateTrack(media_format* mf, uint32 flags)
325 {
326 	return CreateTrack(mf, NULL, flags);
327 }
328 
329 
330 // For BeOS R5 compatibility
331 extern "C" BMediaTrack*
332 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(
333 	BMediaFile* self, media_format* mf, const media_codec_info* mci);
334 BMediaTrack*
335 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(BMediaFile* self,
336 	media_format* mf, const media_codec_info* mci)
337 {
338 	return self->CreateTrack(mf, mci, 0);
339 }
340 
341 
342 // For BeOS R5 compatibility
343 extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format(
344 	BMediaFile* self, media_format* mf);
345 BMediaTrack*
346 CreateTrack__10BMediaFileP12media_format(BMediaFile* self, media_format* mf)
347 {
348 	return self->CreateTrack(mf, NULL, 0);
349 }
350 
351 
352 // Lets you set the copyright info for the entire file
353 status_t
354 BMediaFile::AddCopyright(const char* copyright)
355 {
356 	if (fWriter == NULL)
357 		return B_NO_INIT;
358 
359 	BMetaData* data = new BMetaData();
360 	data->SetString(kCopyright, copyright);
361 	return fWriter->SetMetaData(data);
362 }
363 
364 
365 // Call this to add user-defined chunks to a file (if they're supported)
366 status_t
367 BMediaFile::AddChunk(int32 type, const void* data, size_t size)
368 {
369 	UNIMPLEMENTED();
370 	return B_OK;
371 }
372 
373 
374 // After you have added all the tracks you want, call this
375 status_t
376 BMediaFile::CommitHeader()
377 {
378 	if (fWriter == NULL)
379 		return B_NO_INIT;
380 
381 	return fWriter->CommitHeader();
382 }
383 
384 
385 // After you have written all the data to the track objects, call this
386 status_t
387 BMediaFile::CloseFile()
388 {
389 	if (fWriter == NULL)
390 		return B_NO_INIT;
391 
392 	return fWriter->Close();
393 }
394 
395 // This is for controlling file format parameters
396 
397 // returns a copy of the parameter web
398 status_t
399 BMediaFile::GetParameterWeb(BParameterWeb** outWeb)
400 {
401 	UNIMPLEMENTED();
402 	return B_ERROR;
403 }
404 
405 
406 // deprecated BeOS R5 API
407 BParameterWeb*
408 BMediaFile::Web()
409 {
410 	UNIMPLEMENTED();
411 	return 0;
412 }
413 
414 
415 status_t
416 BMediaFile::GetParameterValue(int32 id,	void* value, size_t* size)
417 {
418 	UNIMPLEMENTED();
419 	return B_OK;
420 }
421 
422 
423 status_t
424 BMediaFile::SetParameterValue(int32 id,	const void* value, size_t size)
425 {
426 	UNIMPLEMENTED();
427 	return B_OK;
428 }
429 
430 
431 BView*
432 BMediaFile::GetParameterView()
433 {
434 	UNIMPLEMENTED();
435 	return 0;
436 }
437 
438 
439 status_t
440 BMediaFile::Perform(int32 selector, void* data)
441 {
442 	UNIMPLEMENTED();
443 	return B_OK;
444 }
445 
446 
447 status_t
448 BMediaFile::ControlFile(int32 selector, void* ioData, size_t size)
449 {
450 	UNIMPLEMENTED();
451 	return B_ERROR;
452 }
453 
454 
455 // #pragma mark - private
456 
457 
458 void
459 BMediaFile::_Init()
460 {
461 	CALLED();
462 
463 	fSource = NULL;
464 	fTrackNum = 0;
465 	fTrackList = NULL;
466 	fExtractor = NULL;
467 	fStreamer = NULL;
468 	fWriter = NULL;
469 	fWriterID = 0;
470 	fErr = B_OK;
471 	fDeleteSource = false;
472 
473 	// not used so far:
474 	fEncoderMgr = NULL;
475 	fWriterMgr = NULL;
476 	fFileClosed = false;
477 }
478 
479 
480 void
481 BMediaFile::_UnInit()
482 {
483 	ReleaseAllTracks();
484 	free(fTrackList);
485 	fTrackList = NULL;
486 	fTrackNum = 0;
487 
488 	// Tells the extractor to stop its asynchronous processing
489 	// before deleting its source
490 	if (fExtractor != NULL)
491 		fExtractor->StopProcessing();
492 
493 	if (fDeleteSource) {
494 		delete fSource;
495 		fSource = NULL;
496 		fDeleteSource = false;
497 	}
498 
499 	// Deleting the extractor or writer can cause unloading of the plugins.
500 	// The source must be deleted before that, because it can come from a
501 	// plugin (for example the http_streamer)
502 	delete fExtractor;
503 	fExtractor = NULL;
504 	delete fWriter;
505 	fWriter = NULL;
506 	delete fStreamer;
507 	fStreamer = NULL;
508 }
509 
510 
511 void
512 BMediaFile::_InitReader(BDataIO* source, const BUrl* url, int32 flags)
513 {
514 	CALLED();
515 
516 	if (source == NULL && url == NULL) {
517 		fErr = B_NO_MEMORY;
518 		return;
519 	}
520 
521 	if (source == NULL)
522 		_InitStreamer(*url, &source);
523 	else if (BFile* file = dynamic_cast<BFile*>(source))
524 		fErr = file->InitCheck();
525 
526 	if (fErr != B_OK)
527 		return;
528 
529 	fExtractor = new(std::nothrow) MediaExtractor(source, flags);
530 
531 	if (fExtractor == NULL)
532 		fErr = B_NO_MEMORY;
533 	else
534 		fErr = fExtractor->InitCheck();
535 
536 	if (fErr != B_OK)
537 		return;
538 
539 	// Get the actual source from the extractor
540 	fSource = fExtractor->Source();
541 
542 	fExtractor->GetFileFormatInfo(&fMFI);
543 	fTrackNum = fExtractor->CountStreams();
544 	fTrackList = (BMediaTrack**)malloc(fTrackNum * sizeof(BMediaTrack*));
545 	if (fTrackList == NULL) {
546 		fErr = B_NO_MEMORY;
547 		return;
548 	}
549 	memset(fTrackList, 0, fTrackNum * sizeof(BMediaTrack*));
550 }
551 
552 
553 void
554 BMediaFile::_InitWriter(BDataIO* target, const BUrl* url,
555 	const media_file_format* fileFormat, int32 flags)
556 {
557 	CALLED();
558 
559 	if (fileFormat == NULL) {
560 		fErr = B_BAD_VALUE;
561 		return;
562 	}
563 
564 	if (target == NULL && url == NULL) {
565 		fErr = B_NO_MEMORY;
566 		return;
567 	}
568 
569 	fMFI = *fileFormat;
570 
571 	if (target == NULL) {
572 		_InitStreamer(*url, &target);
573 		if (fErr != B_OK)
574 			return;
575 	}
576 
577 	fWriter = new(std::nothrow) MediaWriter(target, fMFI);
578 
579 	if (fWriter == NULL)
580 		fErr = B_NO_MEMORY;
581 	else
582 		fErr = fWriter->InitCheck();
583 	if (fErr != B_OK)
584 		return;
585 
586 	// Get the actual source from the writer
587 	fSource = fWriter->Target();
588 	fTrackNum = 0;
589 }
590 
591 
592 void
593 BMediaFile::_InitStreamer(const BUrl& url, BDataIO** adapter)
594 {
595 	if (fStreamer != NULL)
596 		delete fStreamer;
597 
598 	TRACE(url.UrlString());
599 
600 	fStreamer = new(std::nothrow) MediaStreamer(url);
601 	if (fStreamer == NULL) {
602 		fErr = B_NO_MEMORY;
603 		return;
604 	}
605 
606 	fErr = fStreamer->CreateAdapter(adapter);
607 }
608 
609 /*
610 //unimplemented
611 BMediaFile::BMediaFile();
612 BMediaFile::BMediaFile(const BMediaFile&);
613  BMediaFile::BMediaFile& operator=(const BMediaFile&);
614 */
615 
616 status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; }
617 status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; }
618 status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; }
619 status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; }
620 status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; }
621 status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; }
622 status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; }
623 status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; }
624 status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; }
625 status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; }
626 status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; }
627 status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; }
628 status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; }
629 status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; }
630 status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; }
631 status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; }
632 status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; }
633 status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; }
634 status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; }
635 status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; }
636 status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; }
637 status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; }
638 status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; }
639 status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; }
640 status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; }
641 status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; }
642 status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; }
643 status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; }
644 status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; }
645 status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; }
646 status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; }
647 status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; }
648 status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; }
649 status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; }
650 status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; }
651 status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; }
652 status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; }
653 status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; }
654 status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; }
655 status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; }
656 status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; }
657 status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; }
658 status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; }
659 status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; }
660 status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; }
661 status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; }
662 status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; }
663 status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; }
664 
665