xref: /haiku/src/kits/media/MediaFile.cpp (revision 495060760727dd782c9f8a90db71e5d727f19748)
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 	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 		fDeleteSource = false;
483 	}
484 	fSource = NULL;
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 	fSource = source;
527 
528 	fExtractor->GetFileFormatInfo(&fMFI);
529 	fTrackNum = fExtractor->StreamCount();
530 	fTrackList = (BMediaTrack**)malloc(fTrackNum * sizeof(BMediaTrack*));
531 	if (fTrackList == NULL) {
532 		fErr = B_NO_MEMORY;
533 		return;
534 	}
535 	memset(fTrackList, 0, fTrackNum * sizeof(BMediaTrack*));
536 }
537 
538 
539 void
540 BMediaFile::_InitWriter(BDataIO* target, const BUrl* url,
541 	const media_file_format* fileFormat, int32 flags)
542 {
543 	CALLED();
544 
545 	if (fileFormat == NULL) {
546 		fErr = B_BAD_VALUE;
547 		return;
548 	}
549 
550 	if (target == NULL && url == NULL) {
551 		fErr = B_NO_MEMORY;
552 		return;
553 	}
554 
555 	fMFI = *fileFormat;
556 
557 	if (target == NULL) {
558 		_InitStreamer(*url, &target);
559 		if (fErr != B_OK)
560 			return;
561 	}
562 
563 	fWriter = new(std::nothrow) MediaWriter(target, fMFI);
564 
565 	if (fWriter == NULL)
566 		fErr = B_NO_MEMORY;
567 	else
568 		fErr = fWriter->InitCheck();
569 	if (fErr != B_OK)
570 		return;
571 
572 	// Get the actual source from the writer
573 	fSource = fWriter->Target();
574 	fTrackNum = 0;
575 }
576 
577 
578 void
579 BMediaFile::_InitStreamer(const BUrl& url, BDataIO** adapter)
580 {
581 	if (fStreamer != NULL)
582 		delete fStreamer;
583 
584 	TRACE(url.UrlString());
585 
586 	fStreamer = new(std::nothrow) MediaStreamer(url);
587 	if (fStreamer == NULL) {
588 		fErr = B_NO_MEMORY;
589 		return;
590 	}
591 
592 	fErr = fStreamer->CreateAdapter(adapter);
593 }
594 
595 /*
596 //unimplemented
597 BMediaFile::BMediaFile();
598 BMediaFile::BMediaFile(const BMediaFile&);
599  BMediaFile::BMediaFile& operator=(const BMediaFile&);
600 */
601 
602 status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; }
603 status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; }
604 status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; }
605 status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; }
606 status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; }
607 status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; }
608 status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; }
609 status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; }
610 status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; }
611 status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; }
612 status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; }
613 status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; }
614 status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; }
615 status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; }
616 status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; }
617 status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; }
618 status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; }
619 status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; }
620 status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; }
621 status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; }
622 status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; }
623 status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; }
624 status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; }
625 status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; }
626 status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; }
627 status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; }
628 status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; }
629 status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; }
630 status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; }
631 status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; }
632 status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; }
633 status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; }
634 status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; }
635 status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; }
636 status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; }
637 status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; }
638 status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; }
639 status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; }
640 status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; }
641 status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; }
642 status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; }
643 status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; }
644 status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; }
645 status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; }
646 status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; }
647 status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; }
648 status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; }
649 status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; }
650 
651