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