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
25BMediaFile::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
34BMediaFile::BMediaFile(BDataIO* source)
35{
36	CALLED();
37	_Init();
38	_InitReader(source);
39}
40
41
42BMediaFile::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
51BMediaFile::BMediaFile(BDataIO* source, int32 flags)
52{
53	CALLED();
54	_Init();
55	_InitReader(source, NULL, flags);
56}
57
58
59BMediaFile::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
70BMediaFile::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()
80BMediaFile::BMediaFile(const media_file_format* mfi, int32 flags)
81{
82	debugger("BMediaFile::BMediaFile not implemented");
83}
84
85
86BMediaFile::BMediaFile(const BUrl& url)
87{
88	CALLED();
89	_Init();
90	fDeleteSource = true;
91	_InitReader(NULL, &url);
92}
93
94
95BMediaFile::BMediaFile(const BUrl& url, int32 flags)
96{
97	CALLED();
98	_Init();
99	fDeleteSource = true;
100	_InitReader(NULL, &url, flags);
101}
102
103
104BMediaFile::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
118status_t
119BMediaFile::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
134status_t
135BMediaFile::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
149status_t
150BMediaFile::SetTo(const BUrl& url)
151{
152	CALLED();
153
154	_UnInit();
155	_InitReader(NULL, &url);
156
157	return fErr;
158}
159
160
161BMediaFile::~BMediaFile()
162{
163	CALLED();
164
165	_UnInit();
166}
167
168
169status_t
170BMediaFile::InitCheck() const
171{
172	CALLED();
173	return fErr;
174}
175
176
177status_t
178BMediaFile::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
190status_t
191BMediaFile::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
204const char*
205BMediaFile::Copyright() const
206{
207	return fExtractor->Copyright();
208}
209
210
211int32
212BMediaFile::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.
220BMediaTrack*
221BMediaFile::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.
242status_t
243BMediaFile::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
262status_t
263BMediaFile::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
281BMediaTrack*
282BMediaFile::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)
312BMediaTrack*
313BMediaFile::CreateTrack(media_format* mf, uint32 flags)
314{
315	return CreateTrack(mf, NULL, flags);
316}
317
318
319// For BeOS R5 compatibility
320extern "C" BMediaTrack*
321CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(
322	BMediaFile* self, media_format* mf, const media_codec_info* mci);
323BMediaTrack*
324CreateTrack__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
332extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format(
333	BMediaFile* self, media_format* mf);
334BMediaTrack*
335CreateTrack__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
342status_t
343BMediaFile::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)
353status_t
354BMediaFile::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
362status_t
363BMediaFile::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
373status_t
374BMediaFile::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
385status_t
386BMediaFile::GetParameterWeb(BParameterWeb** outWeb)
387{
388	UNIMPLEMENTED();
389	return B_ERROR;
390}
391
392
393// deprecated BeOS R5 API
394BParameterWeb*
395BMediaFile::Web()
396{
397	UNIMPLEMENTED();
398	return 0;
399}
400
401
402status_t
403BMediaFile::GetParameterValue(int32 id,	void* value, size_t* size)
404{
405	UNIMPLEMENTED();
406	return B_OK;
407}
408
409
410status_t
411BMediaFile::SetParameterValue(int32 id,	const void* value, size_t size)
412{
413	UNIMPLEMENTED();
414	return B_OK;
415}
416
417
418BView*
419BMediaFile::GetParameterView()
420{
421	UNIMPLEMENTED();
422	return 0;
423}
424
425
426status_t
427BMediaFile::Perform(int32 selector, void* data)
428{
429	UNIMPLEMENTED();
430	return B_OK;
431}
432
433
434status_t
435BMediaFile::ControlFile(int32 selector, void* ioData, size_t size)
436{
437	UNIMPLEMENTED();
438	return B_ERROR;
439}
440
441
442// #pragma mark - private
443
444
445void
446BMediaFile::_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
467void
468BMediaFile::_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
498void
499BMediaFile::_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
539void
540BMediaFile::_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
578void
579BMediaFile::_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
597BMediaFile::BMediaFile();
598BMediaFile::BMediaFile(const BMediaFile&);
599 BMediaFile::BMediaFile& operator=(const BMediaFile&);
600*/
601
602status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; }
603status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; }
604status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; }
605status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; }
606status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; }
607status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; }
608status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; }
609status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; }
610status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; }
611status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; }
612status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; }
613status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; }
614status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; }
615status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; }
616status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; }
617status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; }
618status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; }
619status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; }
620status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; }
621status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; }
622status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; }
623status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; }
624status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; }
625status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; }
626status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; }
627status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; }
628status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; }
629status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; }
630status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; }
631status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; }
632status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; }
633status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; }
634status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; }
635status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; }
636status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; }
637status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; }
638status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; }
639status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; }
640status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; }
641status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; }
642status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; }
643status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; }
644status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; }
645status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; }
646status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; }
647status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; }
648status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; }
649status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; }
650
651