xref: /haiku/src/kits/media/MediaFile.cpp (revision 6aff37d1c79e20748c683ae224bd629f88a5b0be)
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 "debug.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 	return fExtractor->GetMetaData(_data);
201 }
202 
203 
204 const char*
205 BMediaFile::Copyright() const
206 {
207 	return fExtractor->Copyright();
208 }
209 
210 
211 int32
212 BMediaFile::CountTracks() const
213 {
214 	return fTrackNum;
215 }
216 
217 
218 // Can be called multiple times with the same index.  You must call
219 // ReleaseTrack() when you're done with a track.
220 BMediaTrack*
221 BMediaFile::TrackAt(int32 index)
222 {
223 	CALLED();
224 	if (fTrackList == NULL || fExtractor == NULL
225 		|| index < 0 || index >= fTrackNum) {
226 		return NULL;
227 	}
228 	if (fTrackList[index] == NULL) {
229 		TRACE("BMediaFile::TrackAt, creating new track for index %"
230 			B_PRId32 "\n", index);
231 		fTrackList[index] = new(std::nothrow) BMediaTrack(fExtractor, index);
232 		TRACE("BMediaFile::TrackAt, new track is %p\n", fTrackList[index]);
233 	}
234 	return fTrackList[index];
235 }
236 
237 
238 // Release the resource used by a given BMediaTrack object, to reduce
239 // the memory usage of your application. The specific 'track' object
240 // can no longer be used, but you can create another one by calling
241 // TrackAt() with the same track index.
242 status_t
243 BMediaFile::ReleaseTrack(BMediaTrack* track)
244 {
245 	CALLED();
246 	if (!fTrackList || !track)
247 		return B_ERROR;
248 	for (int32 i = 0; i < fTrackNum; i++) {
249 		if (fTrackList[i] == track) {
250 			TRACE("BMediaFile::ReleaseTrack, releasing track %p with index "
251 				"%" B_PRId32 "\n", track, i);
252 			delete track;
253 			fTrackList[i] = NULL;
254 			return B_OK;
255 		}
256 	}
257 	fprintf(stderr, "BMediaFile::ReleaseTrack track %p not found\n", track);
258 	return B_ERROR;
259 }
260 
261 
262 status_t
263 BMediaFile::ReleaseAllTracks()
264 {
265 	CALLED();
266 	if (!fTrackList)
267 		return B_ERROR;
268 	for (int32 i = 0; i < fTrackNum; i++) {
269 		if (fTrackList[i]) {
270 			TRACE("BMediaFile::ReleaseAllTracks, releasing track %p with "
271 				"index %" B_PRId32 "\n", fTrackList[i], i);
272 			delete fTrackList[i];
273 			fTrackList[i] = NULL;
274 		}
275 	}
276 	return B_OK;
277 }
278 
279 
280 // Create and add a track to the media file
281 BMediaTrack*
282 BMediaFile::CreateTrack(media_format* mediaFormat,
283 	const media_codec_info* codecInfo, uint32 flags)
284 {
285 	if (mediaFormat == NULL)
286 		return NULL;
287 
288 	// NOTE: It is allowed to pass NULL for codecInfo. In that case, the
289 	// track won't have an Encoder and you can only use WriteChunk() with
290 	// already encoded data.
291 
292 	// Make room for the new track.
293 	BMediaTrack** trackList = (BMediaTrack**)realloc(fTrackList,
294 		(fTrackNum + 1) * sizeof(BMediaTrack*));
295 	if (trackList == NULL)
296 		return NULL;
297 
298 	int32 streamIndex = fTrackNum;
299 	fTrackList = trackList;
300 	fTrackNum += 1;
301 
302 	BMediaTrack* track = new(std::nothrow) BMediaTrack(fWriter, streamIndex,
303 		mediaFormat, codecInfo);
304 
305 	fTrackList[streamIndex] = track;
306 
307 	return track;
308 }
309 
310 
311 // Create and add a raw track to the media file (it has no encoder)
312 BMediaTrack*
313 BMediaFile::CreateTrack(media_format* mf, uint32 flags)
314 {
315 	return CreateTrack(mf, NULL, flags);
316 }
317 
318 
319 // For BeOS R5 compatibility
320 extern "C" BMediaTrack*
321 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(
322 	BMediaFile* self, media_format* mf, const media_codec_info* mci);
323 BMediaTrack*
324 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(BMediaFile* self,
325 	media_format* mf, const media_codec_info* mci)
326 {
327 	return self->CreateTrack(mf, mci, 0);
328 }
329 
330 
331 // For BeOS R5 compatibility
332 extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format(
333 	BMediaFile* self, media_format* mf);
334 BMediaTrack*
335 CreateTrack__10BMediaFileP12media_format(BMediaFile* self, media_format* mf)
336 {
337 	return self->CreateTrack(mf, NULL, 0);
338 }
339 
340 
341 // Lets you set the copyright info for the entire file
342 status_t
343 BMediaFile::AddCopyright(const char* copyright)
344 {
345 	if (fWriter == NULL)
346 		return B_NO_INIT;
347 
348 	return fWriter->SetCopyright(copyright);
349 }
350 
351 
352 // Call this to add user-defined chunks to a file (if they're supported)
353 status_t
354 BMediaFile::AddChunk(int32 type, const void* data, size_t size)
355 {
356 	UNIMPLEMENTED();
357 	return B_OK;
358 }
359 
360 
361 // After you have added all the tracks you want, call this
362 status_t
363 BMediaFile::CommitHeader()
364 {
365 	if (fWriter == NULL)
366 		return B_NO_INIT;
367 
368 	return fWriter->CommitHeader();
369 }
370 
371 
372 // After you have written all the data to the track objects, call this
373 status_t
374 BMediaFile::CloseFile()
375 {
376 	if (fWriter == NULL)
377 		return B_NO_INIT;
378 
379 	return fWriter->Close();
380 }
381 
382 // This is for controlling file format parameters
383 
384 // returns a copy of the parameter web
385 status_t
386 BMediaFile::GetParameterWeb(BParameterWeb** outWeb)
387 {
388 	UNIMPLEMENTED();
389 	return B_ERROR;
390 }
391 
392 
393 // deprecated BeOS R5 API
394 BParameterWeb*
395 BMediaFile::Web()
396 {
397 	UNIMPLEMENTED();
398 	return 0;
399 }
400 
401 
402 status_t
403 BMediaFile::GetParameterValue(int32 id,	void* value, size_t* size)
404 {
405 	UNIMPLEMENTED();
406 	return B_OK;
407 }
408 
409 
410 status_t
411 BMediaFile::SetParameterValue(int32 id,	const void* value, size_t size)
412 {
413 	UNIMPLEMENTED();
414 	return B_OK;
415 }
416 
417 
418 BView*
419 BMediaFile::GetParameterView()
420 {
421 	UNIMPLEMENTED();
422 	return 0;
423 }
424 
425 
426 status_t
427 BMediaFile::Perform(int32 selector, void* data)
428 {
429 	UNIMPLEMENTED();
430 	return B_OK;
431 }
432 
433 
434 status_t
435 BMediaFile::ControlFile(int32 selector, void* ioData, size_t size)
436 {
437 	UNIMPLEMENTED();
438 	return B_ERROR;
439 }
440 
441 
442 // #pragma mark - private
443 
444 
445 void
446 BMediaFile::_Init()
447 {
448 	CALLED();
449 
450 	fSource = NULL;
451 	fTrackNum = 0;
452 	fTrackList = NULL;
453 	fExtractor = NULL;
454 	fStreamer = NULL;
455 	fWriter = NULL;
456 	fWriterID = 0;
457 	fErr = B_OK;
458 	fDeleteSource = false;
459 
460 	// not used so far:
461 	fEncoderMgr = NULL;
462 	fWriterMgr = NULL;
463 	fFileClosed = false;
464 }
465 
466 
467 void
468 BMediaFile::_UnInit()
469 {
470 	ReleaseAllTracks();
471 	free(fTrackList);
472 	fTrackList = NULL;
473 	fTrackNum = 0;
474 
475 	// Tells the extractor to stop its asynchronous processing
476 	// before deleting its source
477 	if (fExtractor != NULL)
478 		fExtractor->StopProcessing();
479 
480 	if (fDeleteSource) {
481 		delete fSource;
482 		fSource = NULL;
483 		fDeleteSource = false;
484 	}
485 
486 	// Deleting the extractor or writer can cause unloading of the plugins.
487 	// The source must be deleted before that, because it can come from a
488 	// plugin (for example the http_streamer)
489 	delete fExtractor;
490 	fExtractor = NULL;
491 	delete fWriter;
492 	fWriter = NULL;
493 	delete fStreamer;
494 	fStreamer = NULL;
495 }
496 
497 
498 void
499 BMediaFile::_InitReader(BDataIO* source, const BUrl* url, int32 flags)
500 {
501 	CALLED();
502 
503 	if (source == NULL && url == NULL) {
504 		fErr = B_NO_MEMORY;
505 		return;
506 	}
507 
508 	if (source == NULL)
509 		_InitStreamer(*url, &source);
510 	else if (BFile* file = dynamic_cast<BFile*>(source))
511 		fErr = file->InitCheck();
512 
513 	if (fErr != B_OK)
514 		return;
515 
516 	fExtractor = new(std::nothrow) MediaExtractor(source, flags);
517 
518 	if (fExtractor == NULL)
519 		fErr = B_NO_MEMORY;
520 	else
521 		fErr = fExtractor->InitCheck();
522 
523 	if (fErr != B_OK)
524 		return;
525 
526 	// Get the actual source from the extractor
527 	fSource = fExtractor->Source();
528 
529 	fExtractor->GetFileFormatInfo(&fMFI);
530 	fTrackNum = fExtractor->StreamCount();
531 	fTrackList = (BMediaTrack**)malloc(fTrackNum * sizeof(BMediaTrack*));
532 	if (fTrackList == NULL) {
533 		fErr = B_NO_MEMORY;
534 		return;
535 	}
536 	memset(fTrackList, 0, fTrackNum * sizeof(BMediaTrack*));
537 }
538 
539 
540 void
541 BMediaFile::_InitWriter(BDataIO* target, const BUrl* url,
542 	const media_file_format* fileFormat, int32 flags)
543 {
544 	CALLED();
545 
546 	if (fileFormat == NULL) {
547 		fErr = B_BAD_VALUE;
548 		return;
549 	}
550 
551 	if (target == NULL && url == NULL) {
552 		fErr = B_NO_MEMORY;
553 		return;
554 	}
555 
556 	fMFI = *fileFormat;
557 
558 	if (target == NULL) {
559 		_InitStreamer(*url, &target);
560 		if (fErr != B_OK)
561 			return;
562 	}
563 
564 	fWriter = new(std::nothrow) MediaWriter(target, fMFI);
565 
566 	if (fWriter == NULL)
567 		fErr = B_NO_MEMORY;
568 	else
569 		fErr = fWriter->InitCheck();
570 	if (fErr != B_OK)
571 		return;
572 
573 	// Get the actual source from the writer
574 	fSource = fWriter->Target();
575 	fTrackNum = 0;
576 }
577 
578 
579 void
580 BMediaFile::_InitStreamer(const BUrl& url, BDataIO** adapter)
581 {
582 	if (fStreamer != NULL)
583 		delete fStreamer;
584 
585 	TRACE(url.UrlString());
586 
587 	fStreamer = new(std::nothrow) MediaStreamer(url);
588 	if (fStreamer == NULL) {
589 		fErr = B_NO_MEMORY;
590 		return;
591 	}
592 
593 	fErr = fStreamer->CreateAdapter(adapter);
594 }
595 
596 /*
597 //unimplemented
598 BMediaFile::BMediaFile();
599 BMediaFile::BMediaFile(const BMediaFile&);
600  BMediaFile::BMediaFile& operator=(const BMediaFile&);
601 */
602 
603 status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; }
604 status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; }
605 status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; }
606 status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; }
607 status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; }
608 status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; }
609 status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; }
610 status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; }
611 status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; }
612 status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; }
613 status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; }
614 status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; }
615 status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; }
616 status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; }
617 status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; }
618 status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; }
619 status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; }
620 status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; }
621 status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; }
622 status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; }
623 status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; }
624 status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; }
625 status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; }
626 status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; }
627 status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; }
628 status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; }
629 status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; }
630 status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; }
631 status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; }
632 status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; }
633 status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; }
634 status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; }
635 status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; }
636 status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; }
637 status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; }
638 status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; }
639 status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; }
640 status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; }
641 status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; }
642 status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; }
643 status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; }
644 status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; }
645 status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; }
646 status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; }
647 status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; }
648 status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; }
649 status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; }
650 status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; }
651 
652