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