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