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