xref: /haiku/src/kits/media/MediaTrack.cpp (revision df4074fbed092b09474695aa286752ca41625332)
1 /*
2  * Copyright 2002-2007, Marcus Overhagen <marcus@overhagen.de>
3  * Copyright 2009-2010, Stephan Aßmus <superstippi@gmx.de>
4  * Copyright 2013, Haiku, Inc. All Rights Reserved.
5  * All rights reserved. Distributed under the terms of the MIT license.
6  *
7  * Authors:
8  *		Stephan Aßmus, superstippi@gmx.de
9  *		Marcus Overhagen, marcus@overhagen.de
10  */
11 
12 
13 #include <MediaTrack.h>
14 
15 #include <new>
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include <Roster.h>
22 
23 #include "MediaExtractor.h"
24 #include "MediaWriter.h"
25 #include "PluginManager.h"
26 
27 
28 //#define TRACE_MEDIA_TRACK
29 #ifdef TRACE_MEDIA_TRACK
30 #	ifndef TRACE
31 #		define TRACE printf
32 #	endif
33 #else
34 #	ifndef TRACE
35 #		define TRACE(a...)
36 #	endif
37 #endif
38 
39 #define ERROR(a...) fprintf(stderr, a)
40 
41 
42 #define CONVERT_TO_INT32 0
43 	// TODO: Test! This triggers a few bugs!
44 
45 // flags used for workarounds
46 enum {
47 	FORCE_RAW_AUDIO 				= 0x0001,
48 	FORCE_RAW_VIDEO 				= 0x0002,
49 	FORCE_RAW_AUDIO_INT16_FORMAT 	= 0x0010,
50 	FORCE_RAW_AUDIO_INT32_FORMAT 	= 0x0020,
51 	FORCE_RAW_AUDIO_FLOAT_FORMAT 	= 0x0040,
52 	FORCE_RAW_AUDIO_HOST_ENDIAN 	= 0x0100,
53 	IGNORE_ENCODED_AUDIO 			= 0x1000,
54 	IGNORE_ENCODED_VIDEO 			= 0x2000,
55 };
56 
57 #define B_MEDIA_DISABLE_FORMAT_TRANSLATION 0x4000
58 	// TODO: move this (after name change?) to MediaDefs.h
59 
60 
61 class RawDecoderChunkProvider : public ChunkProvider {
62 public:
63 							RawDecoderChunkProvider(Decoder* decoder,
64 								int buffer_size, int frame_size);
65 	virtual					~RawDecoderChunkProvider();
66 
67 			status_t		GetNextChunk(const void** chunkBuffer,
68 								size_t* chunkSize,
69 								media_header* mediaHeader);
70 
71 private:
72 			Decoder*		fDecoder;
73 			void*			fBuffer;
74 			int				fBufferSize;
75 			int				fFrameSize;
76 };
77 
78 
79 /*************************************************************
80  * protected BMediaTrack
81  *************************************************************/
82 
83 BMediaTrack::~BMediaTrack()
84 {
85 	CALLED();
86 
87 	gPluginManager.DestroyDecoder(fRawDecoder);
88 	gPluginManager.DestroyDecoder(fDecoder);
89 	gPluginManager.DestroyEncoder(fEncoder);
90 }
91 
92 /*************************************************************
93  * public BMediaTrack
94  *************************************************************/
95 
96 status_t
97 BMediaTrack::InitCheck() const
98 {
99 	CALLED();
100 
101 	return fInitStatus;
102 }
103 
104 
105 status_t
106 BMediaTrack::GetCodecInfo(media_codec_info* _codecInfo) const
107 {
108 	CALLED();
109 
110 	if (fDecoder == NULL)
111 		return B_NO_INIT;
112 
113 	*_codecInfo = fCodecInfo;
114 	strlcpy(_codecInfo->pretty_name, fCodecInfo.pretty_name,
115 		sizeof(_codecInfo->pretty_name));
116 
117 	return B_OK;
118 }
119 
120 
121 status_t
122 BMediaTrack::EncodedFormat(media_format* _format) const
123 {
124 	CALLED();
125 
126 	if (_format == NULL)
127 		return B_BAD_VALUE;
128 
129 	if (fExtractor == NULL)
130 		return B_NO_INIT;
131 
132 	*_format = *fExtractor->EncodedFormat(fStream);
133 
134 #ifdef TRACE_MEDIA_TRACK
135 	char s[200];
136 	string_for_format(*_format, s, sizeof(s));
137 	printf("BMediaTrack::EncodedFormat: %s\n", s);
138 #endif
139 
140 	return B_OK;
141 }
142 
143 
144 // for BeOS R5 compatibility
145 extern "C" status_t DecodedFormat__11BMediaTrackP12media_format(
146 	BMediaTrack* self, media_format* _format);
147 
148 status_t DecodedFormat__11BMediaTrackP12media_format(BMediaTrack* self,
149 	media_format* _format)
150 {
151 	return self->DecodedFormat(_format, 0);
152 }
153 
154 
155 status_t
156 BMediaTrack::DecodedFormat(media_format* _format, uint32 flags)
157 {
158 	CALLED();
159 
160 	if (_format == NULL)
161 		return B_BAD_VALUE;
162 
163 	if (fExtractor == NULL || fDecoder == NULL)
164 		return B_NO_INIT;
165 
166 	gPluginManager.DestroyDecoder(fRawDecoder);
167 	fRawDecoder = NULL;
168 
169 #ifdef TRACE_MEDIA_TRACK
170 	char s[200];
171 	string_for_format(*_format, s, sizeof(s));
172 	printf("BMediaTrack::DecodedFormat: req1: %s\n", s);
173 #endif
174 
175 	if ((fWorkaroundFlags & FORCE_RAW_AUDIO)
176 		|| ((fWorkaroundFlags & IGNORE_ENCODED_AUDIO)
177 			&& _format->type == B_MEDIA_ENCODED_AUDIO)) {
178 		_format->type = B_MEDIA_RAW_AUDIO;
179 		_format->u.raw_audio = media_multi_audio_format::wildcard;
180 	}
181 	if ((fWorkaroundFlags & FORCE_RAW_VIDEO)
182 		|| ((fWorkaroundFlags & IGNORE_ENCODED_VIDEO)
183 			&& _format->type == B_MEDIA_ENCODED_VIDEO)) {
184 		_format->type = B_MEDIA_RAW_VIDEO;
185 		_format->u.raw_video = media_raw_video_format::wildcard;
186 	}
187 	if (_format->type == B_MEDIA_RAW_AUDIO) {
188 		if (fWorkaroundFlags & FORCE_RAW_AUDIO_HOST_ENDIAN)
189 			_format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
190 
191 		if (fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT) {
192 			_format->u.raw_audio.format
193 				= media_raw_audio_format::B_AUDIO_SHORT;
194 		}
195 		if (fWorkaroundFlags & FORCE_RAW_AUDIO_INT32_FORMAT) {
196 			_format->u.raw_audio.format
197 				= media_raw_audio_format::B_AUDIO_INT;
198 		}
199 		if (fWorkaroundFlags & FORCE_RAW_AUDIO_FLOAT_FORMAT) {
200 			_format->u.raw_audio.format
201 				= media_raw_audio_format::B_AUDIO_FLOAT;
202 		}
203 	}
204 
205 #ifdef TRACE_MEDIA_TRACK
206 	string_for_format(*_format, s, sizeof(s));
207 	printf("BMediaTrack::DecodedFormat: req2: %s\n", s);
208 #endif
209 
210 	fFormat = *_format;
211 	status_t result = fDecoder->NegotiateOutputFormat(_format);
212 
213 #ifdef TRACE_MEDIA_TRACK
214 	string_for_format(*_format, s, sizeof(s));
215 	printf("BMediaTrack::DecodedFormat: nego: %s\n", s);
216 #endif
217 
218 	if (_format->type == 0) {
219 #ifdef TRACE_MEDIA_TRACK
220 		printf("BMediaTrack::DecodedFormat: Decoder didn't set output format "
221 			"type.\n");
222 #endif
223 	}
224 
225 	if (_format->type == B_MEDIA_RAW_AUDIO) {
226 		if (_format->u.raw_audio.byte_order == 0) {
227 #ifdef TRACE_MEDIA_TRACK
228 			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw audio "
229 				"output byte order.\n");
230 #endif
231 		}
232 		if (_format->u.raw_audio.format == 0) {
233 #ifdef TRACE_MEDIA_TRACK
234 			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw audio "
235 				"output sample format.\n");
236 #endif
237 		}
238 		if (_format->u.raw_audio.buffer_size <= 0) {
239 #ifdef TRACE_MEDIA_TRACK
240 			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw audio "
241 				"output buffer size.\n");
242 #endif
243 		}
244 	}
245 
246 	if (_format->type == B_MEDIA_RAW_VIDEO) {
247 		if (_format->u.raw_video.display.format == 0) {
248 #ifdef TRACE_MEDIA_TRACK
249 			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw video "
250 				"output color space.\n");
251 #endif
252 		}
253 		if (_format->u.raw_video.display.line_width == 0) {
254 #ifdef TRACE_MEDIA_TRACK
255 			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw video "
256 				"output line_width.\n");
257 #endif
258 		}
259 		if (_format->u.raw_video.display.line_count == 0) {
260 #ifdef TRACE_MEDIA_TRACK
261 			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw video "
262 				"output line_count.\n");
263 #endif
264 		}
265 		if (_format->u.raw_video.display.bytes_per_row == 0) {
266 #ifdef TRACE_MEDIA_TRACK
267 			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw video "
268 				"output bytes_per_row.\n");
269 #endif
270 		}
271 	}
272 
273 	if ((flags & B_MEDIA_DISABLE_FORMAT_TRANSLATION) == 0) {
274 		if (fFormat.type == B_MEDIA_RAW_AUDIO
275 			&& _format->type == B_MEDIA_RAW_AUDIO
276 			&& fFormat.u.raw_audio.format != 0
277 			&& fFormat.u.raw_audio.format != _format->u.raw_audio.format) {
278 			if (SetupFormatTranslation(*_format, &fFormat))
279 				*_format = fFormat;
280 		}
281 	}
282 
283 	fFormat = *_format;
284 
285 //	string_for_format(*_format, s, sizeof(s));
286 //	printf("BMediaTrack::DecodedFormat: status: %s\n", s);
287 	return result;
288 }
289 
290 
291 status_t
292 BMediaTrack::GetMetaData(BMessage* _data) const
293 {
294 	CALLED();
295 
296 	if (fExtractor == NULL)
297 		return B_NO_INIT;
298 
299 	if (_data == NULL)
300 		return B_BAD_VALUE;
301 
302 	_data->MakeEmpty();
303 
304 	BMetaData data;
305 	if (fExtractor->GetStreamMetaData(fStream, &data) != B_OK) {
306 		*_data = *data.Message();
307 		return B_OK;
308 	}
309 	return B_ERROR;
310 }
311 
312 
313 int64
314 BMediaTrack::CountFrames() const
315 {
316 	CALLED();
317 
318 	int64 frames = fExtractor ? fExtractor->CountFrames(fStream) : 0;
319 //	printf("BMediaTrack::CountFrames: %lld\n", frames);
320 	return frames;
321 }
322 
323 
324 bigtime_t
325 BMediaTrack::Duration() const
326 {
327 	CALLED();
328 
329 	bigtime_t duration = fExtractor ? fExtractor->Duration(fStream) : 0;
330 //	printf("BMediaTrack::Duration: %lld\n", duration);
331 	return duration;
332 }
333 
334 
335 int64
336 BMediaTrack::CurrentFrame() const
337 {
338 	return fCurrentFrame;
339 }
340 
341 
342 bigtime_t
343 BMediaTrack::CurrentTime() const
344 {
345 	return fCurrentTime;
346 }
347 
348 // BMediaTrack::ReadFrames(char*, long long*, media_header*)
349 // Compatibility for R5 and below. Required by Corum III and Civ:CTP.
350 #if __GNUC__ < 3
351 
352 extern "C" status_t
353 ReadFrames__11BMediaTrackPcPxP12media_header(BMediaTrack* self,
354 	char* _buffer, int64* _frameCount, media_header* header)
355 {
356 	return self->ReadFrames(_buffer, _frameCount, header, 0);
357 }
358 
359 #endif	// __GNUC__ < 3
360 
361 status_t
362 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount, media_header* header)
363 {
364 	return ReadFrames(buffer, _frameCount, header, NULL);
365 }
366 
367 
368 status_t
369 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount,
370 	media_header* _header, media_decode_info* info)
371 {
372 //	CALLED();
373 
374 	if (fDecoder == NULL)
375 		return B_NO_INIT;
376 
377 	if (buffer == NULL || _frameCount == NULL)
378 		return B_BAD_VALUE;
379 
380 	media_header header;
381 	if (_header == NULL)
382 		_header = &header;
383 
384 	// Always clear the header first, as the decoder may not set all fields.
385 	memset(_header, 0, sizeof(media_header));
386 
387 	status_t result = fRawDecoder != NULL
388 		? fRawDecoder->Decode(buffer, _frameCount, _header, info)
389 		: fDecoder->Decode(buffer, _frameCount, _header, info);
390 
391 	if (result == B_OK) {
392 		fCurrentFrame += *_frameCount;
393 		bigtime_t framesDuration = (bigtime_t)(*_frameCount * 1000000
394 			/ _FrameRate());
395 		fCurrentTime = _header->start_time + framesDuration;
396 #if 0
397 	// This debug output shows drift between calculated fCurrentFrame and
398 	// time-based current frame, if there is any.
399 	if (fFormat.type == B_MEDIA_RAW_AUDIO) {
400 		printf("current frame: %lld / calculated: %lld (%.2f/%.2f)\r",
401 			fCurrentFrame,
402 			int64(fCurrentTime * _FrameRate() / 1000000.0 + 0.5),
403 			fCurrentTime / 1000000.0, (float)fCurrentFrame / _FrameRate());
404 		fflush(stdout);
405 	}
406 #endif
407 	} else {
408 		ERROR("BMediaTrack::ReadFrames: decoder returned error %#" B_PRIx32
409 			" (%s)\n", result, strerror(result));
410 		*_frameCount = 0;
411 	}
412 
413 #if 0
414 	PRINT(1, "BMediaTrack::ReadFrames: stream %ld, start-time %5Ld.%06Ld, "
415 		"%lld frames\n", fStream,  _header->start_time / 1000000,
416 		_header->start_time % 1000000, *out_frameCount);
417 #endif
418 
419 	return result;
420 }
421 
422 
423 status_t
424 BMediaTrack::ReplaceFrames(const void* inBuffer, int64* _frameCount,
425 	const media_header* header)
426 {
427 	UNIMPLEMENTED();
428 
429 	// TODO: Actually, a file is either open for reading or writing at the
430 	// moment. Since the chunk size of encoded media data will change,
431 	// implementing this call will only be possible for raw media tracks.
432 
433 	return B_NOT_SUPPORTED;
434 }
435 
436 
437 status_t
438 BMediaTrack::SeekToTime(bigtime_t* _time, int32 flags)
439 {
440 	CALLED();
441 
442 	if (fDecoder == NULL || fExtractor == NULL)
443 		return B_NO_INIT;
444 
445 	if (_time == NULL)
446 		return B_BAD_VALUE;
447 
448 	// Make sure flags are valid
449 	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME;
450 
451 	#if DEBUG
452 	bigtime_t requestedTime = *_time;
453 	#endif
454 	int64 frame = 0;
455 
456 	status_t result = fExtractor->Seek(fStream, flags, &frame, _time);
457 	if (result != B_OK) {
458 		ERROR("BMediaTrack::SeekToTime: extractor seek failed\n");
459 		return result;
460 	}
461 
462 	result = fDecoder->SeekedTo(frame, *_time);
463 	if (result != B_OK) {
464 		ERROR("BMediaTrack::SeekToTime: decoder seek failed\n");
465 		return result;
466 	}
467 
468 	if (fRawDecoder != NULL) {
469 		result = fRawDecoder->SeekedTo(frame, *_time);
470 		if (result != B_OK) {
471 			ERROR("BMediaTrack::SeekToTime: raw decoder seek failed\n");
472 			return result;
473 		}
474 	}
475 
476 	fCurrentFrame = frame;
477 	fCurrentTime = *_time;
478 
479 	PRINT(1, "BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n",
480 		requestedTime / 1000000.0, *_time / 1000000.0);
481 
482 	return B_OK;
483 }
484 
485 
486 status_t
487 BMediaTrack::SeekToFrame(int64* _frame, int32 flags)
488 {
489 	CALLED();
490 
491 	if (fDecoder == NULL || fExtractor == NULL)
492 		return B_NO_INIT;
493 
494 	if (_frame == NULL)
495 		return B_BAD_VALUE;
496 
497 	// Make sure flags are valid
498 	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_FRAME;
499 
500 	#if DEBUG
501 	int64 requestedFrame = *_frame;
502 	#endif
503 	bigtime_t time = 0;
504 
505 	status_t result = fExtractor->Seek(fStream, flags, _frame, &time);
506 	if (result != B_OK) {
507 		ERROR("BMediaTrack::SeekToFrame: extractor seek failed\n");
508 		return result;
509 	}
510 
511 	result = fDecoder->SeekedTo(*_frame, time);
512 	if (result != B_OK) {
513 		ERROR("BMediaTrack::SeekToFrame: decoder seek failed\n");
514 		return result;
515 	}
516 
517 	if (fRawDecoder != NULL) {
518 		result = fRawDecoder->SeekedTo(*_frame, time);
519 		if (result != B_OK) {
520 			ERROR("BMediaTrack::SeekToFrame: raw decoder seek failed\n");
521 			return result;
522 		}
523 	}
524 
525 	fCurrentFrame = *_frame;
526 	fCurrentTime = time;
527 
528 	PRINT(1, "BMediaTrack::SeekToTime SeekToFrame, requested %lld, "
529 		"result %lld\n", requestedFrame, *_frame);
530 
531 	return B_OK;
532 }
533 
534 
535 status_t
536 BMediaTrack::FindKeyFrameForTime(bigtime_t* _time, int32 flags) const
537 {
538 	CALLED();
539 
540 	if (fExtractor == NULL)
541 		return B_NO_INIT;
542 
543 	if (_time == NULL)
544 		return B_BAD_VALUE;
545 
546 	// Make sure flags are valid
547 	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME;
548 
549 	int64 frame = 0;
550 		// dummy frame, will be ignored because of flags
551 	status_t result = fExtractor->FindKeyFrame(fStream, flags, &frame, _time);
552 	if (result != B_OK) {
553 		ERROR("BMediaTrack::FindKeyFrameForTime: extractor seek failed: %s\n",
554 			strerror(result));
555 	}
556 
557 	return result;
558 }
559 
560 
561 status_t
562 BMediaTrack::FindKeyFrameForFrame(int64* _frame, int32 flags) const
563 {
564 	CALLED();
565 
566 	if (fExtractor == NULL)
567 		return B_NO_INIT;
568 
569 	if (_frame == NULL)
570 		return B_BAD_VALUE;
571 
572 	// Make sure flags are valid
573 	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_FRAME;
574 
575 	bigtime_t time = 0;
576 		// dummy time, will be ignored because of flags
577 	status_t result = fExtractor->FindKeyFrame(fStream, flags, _frame, &time);
578 	if (result != B_OK) {
579 		ERROR("BMediaTrack::FindKeyFrameForFrame: extractor seek failed: %s\n",
580 			strerror(result));
581 	}
582 
583 	return result;
584 }
585 
586 
587 status_t
588 BMediaTrack::ReadChunk(char** _buffer, int32* _size, media_header* _header)
589 {
590 	CALLED();
591 
592 	if (fExtractor == NULL)
593 		return B_NO_INIT;
594 
595 	if (_buffer == NULL || _size == NULL)
596 		return B_BAD_VALUE;
597 
598 	media_header header;
599 	if (_header == NULL)
600 		_header = &header;
601 
602 	// Always clear the header first, as the extractor may not set all fields.
603 	memset(_header, 0, sizeof(media_header));
604 
605 	const void* buffer;
606 	size_t size;
607 	status_t result = fExtractor->GetNextChunk(fStream, &buffer, &size,
608 		_header);
609 
610 	if (result == B_OK) {
611 		*_buffer = const_cast<char*>(static_cast<const char*>(buffer));
612 			// TODO: Change the pointer type when we break the API.
613 		*_size = size;
614 		// TODO: This changes the meaning of fCurrentTime from pointing
615 		// to the next chunk start time (i.e. after seeking) to the start time
616 		// of the last chunk. Asking the extractor for the current time will
617 		// not work so well because of the chunk cache. But providing a
618 		// "duration" field in the media_header could be useful.
619 		fCurrentTime = _header->start_time;
620 		fCurrentFrame = (int64)(fCurrentTime * _FrameRate() / 1000000LL);
621 
622 	}
623 
624 	return result;
625 }
626 
627 
628 status_t
629 BMediaTrack::AddCopyright(const char* copyright)
630 {
631 	if (fWriter == NULL)
632 		return B_NO_INIT;
633 
634 	BMetaData* data = new BMetaData();
635 	data->SetString(kCopyright, copyright);
636 	return fWriter->SetMetaData(data);
637 }
638 
639 
640 status_t
641 BMediaTrack::AddTrackInfo(uint32 code, const void* data, size_t size,
642 	uint32 flags)
643 {
644 	if (fWriter == NULL)
645 		return B_NO_INIT;
646 
647 	return fWriter->AddTrackInfo(fStream, code, data, size, flags);
648 }
649 
650 
651 status_t
652 BMediaTrack::WriteFrames(const void* data, int32 frameCount, int32 flags)
653 {
654 	media_encode_info encodeInfo;
655 	encodeInfo.flags = flags;
656 
657 	return WriteFrames(data, frameCount, &encodeInfo);
658 }
659 
660 
661 status_t
662 BMediaTrack::WriteFrames(const void* data, int64 frameCount,
663 	media_encode_info* info)
664 {
665 	if (fEncoder == NULL)
666 		return B_NO_INIT;
667 
668 	return fEncoder->Encode(data, frameCount, info);
669 }
670 
671 
672 status_t
673 BMediaTrack::WriteChunk(const void* data, size_t size, uint32 flags)
674 {
675 	media_encode_info encodeInfo;
676 	encodeInfo.flags = flags;
677 
678 	return WriteChunk(data, size, &encodeInfo);
679 }
680 
681 
682 status_t
683 BMediaTrack::WriteChunk(const void* data, size_t size, media_encode_info* info)
684 {
685 	if (fWriter == NULL)
686 		return B_NO_INIT;
687 
688 	return fWriter->WriteChunk(fStream, data, size, info);
689 }
690 
691 
692 status_t
693 BMediaTrack::Flush()
694 {
695 	if (fWriter == NULL)
696 		return B_NO_INIT;
697 
698 	return fWriter->Flush();
699 }
700 
701 
702 // deprecated BeOS R5 API
703 BParameterWeb*
704 BMediaTrack::Web()
705 {
706 	BParameterWeb* web;
707 	if (GetParameterWeb(&web) == B_OK)
708 		return web;
709 
710 	return NULL;
711 }
712 
713 
714 status_t
715 BMediaTrack::GetParameterWeb(BParameterWeb** outWeb)
716 {
717 	if (outWeb == NULL)
718 		return B_BAD_VALUE;
719 
720 	if (fEncoder == NULL)
721 		return B_NO_INIT;
722 
723 	// TODO: This method is new in Haiku. The header mentions it returns a
724 	// copy. But how could it even do that? How can one clone a web and make
725 	// it point to the same BControllable?
726 	*outWeb = fEncoder->ParameterWeb();
727 	if (*outWeb != NULL)
728 		return B_OK;
729 
730 	return B_NOT_SUPPORTED;
731 }
732 
733 
734 status_t
735 BMediaTrack::GetParameterValue(int32 id, void* value, size_t* size)
736 {
737 	if (value == NULL || size == NULL)
738 		return B_BAD_VALUE;
739 
740 	if (fEncoder == NULL)
741 		return B_NO_INIT;
742 
743 	return fEncoder->GetParameterValue(id, value, size);
744 }
745 
746 
747 status_t
748 BMediaTrack::SetParameterValue(int32 id, const void* value, size_t size)
749 {
750 	if (value == NULL || size == 0)
751 		return B_BAD_VALUE;
752 
753 	if (fEncoder == NULL)
754 		return B_NO_INIT;
755 
756 	return fEncoder->SetParameterValue(id, value, size);
757 }
758 
759 
760 BView*
761 BMediaTrack::GetParameterView()
762 {
763 	if (fEncoder == NULL)
764 		return NULL;
765 
766 	return fEncoder->ParameterView();
767 }
768 
769 
770 status_t
771 BMediaTrack::GetQuality(float* quality)
772 {
773 	if (quality == NULL)
774 		return B_BAD_VALUE;
775 
776 	encode_parameters parameters;
777 	status_t result = GetEncodeParameters(&parameters);
778 	if (result != B_OK)
779 		return result;
780 
781 	*quality = parameters.quality;
782 
783 	return B_OK;
784 }
785 
786 
787 status_t
788 BMediaTrack::SetQuality(float quality)
789 {
790 	encode_parameters parameters;
791 	status_t result = GetEncodeParameters(&parameters);
792 	if (result != B_OK)
793 		return result;
794 
795 	if (quality < 0.0f)
796 		quality = 0.0f;
797 
798 	if (quality > 1.0f)
799 		quality = 1.0f;
800 
801 	parameters.quality = quality;
802 
803 	return SetEncodeParameters(&parameters);
804 }
805 
806 
807 status_t
808 BMediaTrack::GetEncodeParameters(encode_parameters* parameters) const
809 {
810 	if (parameters == NULL)
811 		return B_BAD_VALUE;
812 
813 	if (fEncoder == NULL)
814 		return B_NO_INIT;
815 
816 	return fEncoder->GetEncodeParameters(parameters);
817 }
818 
819 
820 status_t
821 BMediaTrack::SetEncodeParameters(encode_parameters* parameters)
822 {
823 	if (parameters == NULL)
824 		return B_BAD_VALUE;
825 
826 	if (fEncoder == NULL)
827 		return B_NO_INIT;
828 
829 	return fEncoder->SetEncodeParameters(parameters);
830 }
831 
832 
833 status_t
834 BMediaTrack::Perform(int32 selector, void* data)
835 {
836 	return B_OK;
837 }
838 
839 // #pragma mark - private
840 
841 
842 BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor* extractor,
843 	int32 stream)
844 {
845 	CALLED();
846 
847 	fWorkaroundFlags = 0;
848 	fDecoder = NULL;
849 	fRawDecoder = NULL;
850 	fExtractor = extractor;
851 	fStream = stream;
852 	fInitStatus = B_OK;
853 
854 	SetupWorkaround();
855 
856 	status_t ret = fExtractor->CreateDecoder(fStream, &fDecoder, &fCodecInfo);
857 	if (ret != B_OK) {
858 		TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
859 			"%s\n", strerror(ret));
860 		// We do not set fInitStatus here, because ReadChunk should still work.
861 		fDecoder = NULL;
862 	}
863 
864 	fCurrentFrame = 0;
865 	fCurrentTime = 0;
866 
867 	// not used:
868 	fEncoder = NULL;
869 	fEncoderID = 0;
870 	fWriter = NULL;
871 }
872 
873 
874 BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
875 	int32 streamIndex, media_format* format,
876 	const media_codec_info* codecInfo)
877 {
878 	CALLED();
879 
880 	fWorkaroundFlags = 0;
881 	fEncoder = NULL;
882 	fEncoderID = -1;
883 		// TODO: Not yet sure what this was needed for...
884 	fWriter = writer;
885 	fStream = streamIndex;
886 	fInitStatus = B_OK;
887 
888 	SetupWorkaround();
889 
890 	if (codecInfo != NULL) {
891 		status_t ret = fWriter->CreateEncoder(&fEncoder, codecInfo, format);
892 		if (ret != B_OK) {
893 			TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
894 				"%s\n", strerror(ret));
895 			// We do not set fInitStatus here, because WriteChunk should still
896 			// work.
897 			fEncoder = NULL;
898 		} else {
899 			fCodecInfo = *codecInfo;
900 			fInitStatus = fEncoder->SetUp(format);
901 		}
902 	}
903 
904 	fFormat = *format;
905 
906 	// not used:
907 	fCurrentFrame = 0;
908 	fCurrentTime = 0;
909 	fDecoder = NULL;
910 	fRawDecoder = NULL;
911 	fExtractor = NULL;
912 }
913 
914 
915 // Does nothing, returns B_ERROR, for Zeta compatiblity only
916 status_t
917 BMediaTrack::ControlCodec(int32 selector, void* io_data, size_t size)
918 {
919 	return B_ERROR;
920 }
921 
922 
923 void
924 BMediaTrack::SetupWorkaround()
925 {
926 	app_info	ainfo;
927 	thread_info	tinfo;
928 
929 	get_thread_info(find_thread(0), &tinfo);
930 	be_roster->GetRunningAppInfo(tinfo.team, &ainfo);
931 
932 	if (strcmp(ainfo.signature, "application/x-vnd.marcone-soundplay") == 0) {
933 		fWorkaroundFlags = FORCE_RAW_AUDIO | FORCE_RAW_AUDIO_INT16_FORMAT
934 			| FORCE_RAW_AUDIO_HOST_ENDIAN;
935 		printf("BMediaTrack::SetupWorkaround: SoundPlay workaround active\n");
936 	}
937 	if (strcmp(ainfo.signature, "application/x-vnd.Be.MediaPlayer") == 0) {
938 		fWorkaroundFlags = IGNORE_ENCODED_AUDIO | IGNORE_ENCODED_VIDEO;
939 		printf("BMediaTrack::SetupWorkaround: MediaPlayer workaround active\n");
940 	}
941 
942 #if CONVERT_TO_INT32
943 	// TODO: Test
944 	if (!(fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT))
945 		fWorkaroundFlags |= FORCE_RAW_AUDIO_INT32_FORMAT;
946 #endif
947 }
948 
949 
950 bool
951 BMediaTrack::SetupFormatTranslation(const media_format &from, media_format* to)
952 {
953 	gPluginManager.DestroyDecoder(fRawDecoder);
954 	fRawDecoder = NULL;
955 
956 #ifdef TRACE_MEDIA_TRACK
957 	char s[200];
958 	string_for_format(from, s, sizeof(s));
959 	printf("BMediaTrack::SetupFormatTranslation: from: %s\n", s);
960 #endif
961 
962 	status_t result = gPluginManager.CreateDecoder(&fRawDecoder, from);
963 	if (result != B_OK) {
964 		ERROR("BMediaTrack::SetupFormatTranslation: CreateDecoder failed\n");
965 		return false;
966 	}
967 
968 	// XXX video?
969 	int buffer_size = from.u.raw_audio.buffer_size;
970 	int frame_size = (from.u.raw_audio.format & 15)
971 		* from.u.raw_audio.channel_count;
972 	media_format fromNotConst = from;
973 
974 	ChunkProvider* chunkProvider
975 		= new (std::nothrow) RawDecoderChunkProvider(fDecoder, buffer_size,
976 			frame_size);
977 	if (chunkProvider == NULL) {
978 		ERROR("BMediaTrack::SetupFormatTranslation: can't create chunk "
979 			"provider\n");
980 		goto error;
981 	}
982 	fRawDecoder->SetChunkProvider(chunkProvider);
983 
984 	result = fRawDecoder->Setup(&fromNotConst, 0, 0);
985 	if (result != B_OK) {
986 		ERROR("BMediaTrack::SetupFormatTranslation: Setup failed\n");
987 		goto error;
988 	}
989 
990 #ifdef TRACE_MEDIA_TRACK
991 	string_for_format(*to, s, sizeof(s));
992 	printf("BMediaTrack::SetupFormatTranslation:   to: %s\n", s);
993 #endif
994 
995 	result = fRawDecoder->NegotiateOutputFormat(to);
996 	if (result != B_OK) {
997 		ERROR("BMediaTrack::SetupFormatTranslation: NegotiateOutputFormat "
998 			"failed\n");
999 		goto error;
1000 	}
1001 
1002 #ifdef TRACE_MEDIA_TRACK
1003 	string_for_format(*to, s, sizeof(s));
1004 	printf("BMediaTrack::SetupFormatTranslation:  result: %s\n", s);
1005 #endif
1006 
1007 	return true;
1008 
1009 error:
1010 	gPluginManager.DestroyDecoder(fRawDecoder);
1011 	fRawDecoder = NULL;
1012 	return false;
1013 }
1014 
1015 
1016 double
1017 BMediaTrack::_FrameRate() const
1018 {
1019 	switch (fFormat.type) {
1020 		case B_MEDIA_RAW_VIDEO:
1021 			return fFormat.u.raw_video.field_rate;
1022 		case B_MEDIA_ENCODED_VIDEO:
1023 			return fFormat.u.encoded_video.output.field_rate;
1024 		case B_MEDIA_RAW_AUDIO:
1025 			return fFormat.u.raw_audio.frame_rate;
1026 		case B_MEDIA_ENCODED_AUDIO:
1027 			return fFormat.u.encoded_audio.output.frame_rate;
1028 		default:
1029 			return 1.0;
1030 	}
1031 }
1032 
1033 #if 0
1034 // unimplemented
1035 BMediaTrack::BMediaTrack()
1036 BMediaTrack::BMediaTrack(const BMediaTrack &)
1037 BMediaTrack &BMediaTrack::operator=(const BMediaTrack &)
1038 #endif
1039 
1040 status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; }
1041 status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; }
1042 status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; }
1043 status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; }
1044 status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; }
1045 status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; }
1046 status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; }
1047 status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; }
1048 status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; }
1049 status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; }
1050 status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; }
1051 status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; }
1052 status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; }
1053 status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; }
1054 status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; }
1055 status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; }
1056 status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; }
1057 status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; }
1058 status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; }
1059 status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; }
1060 status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; }
1061 status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; }
1062 status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; }
1063 status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; }
1064 status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; }
1065 status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; }
1066 status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; }
1067 status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; }
1068 status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; }
1069 status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; }
1070 status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; }
1071 status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; }
1072 status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; }
1073 status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; }
1074 status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; }
1075 status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; }
1076 status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; }
1077 status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; }
1078 status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; }
1079 status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; }
1080 status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; }
1081 status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; }
1082 status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; }
1083 status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; }
1084 status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; }
1085 status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; }
1086 status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; }
1087 status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; }
1088 
1089 
1090 RawDecoderChunkProvider::RawDecoderChunkProvider(Decoder* decoder,
1091 	int buffer_size, int frame_size)
1092 {
1093 //	printf("RawDecoderChunkProvider: buffer_size %d, frame_size %d\n",
1094 //		buffer_size, frame_size);
1095 	fDecoder = decoder;
1096 	fFrameSize = frame_size;
1097 	fBufferSize = buffer_size;
1098 	fBuffer = malloc(buffer_size);
1099 }
1100 
1101 
1102 RawDecoderChunkProvider::~RawDecoderChunkProvider()
1103 {
1104 	free(fBuffer);
1105 }
1106 
1107 
1108 status_t
1109 RawDecoderChunkProvider::GetNextChunk(const void** chunkBuffer,
1110 	size_t* chunkSize, media_header* header)
1111 {
1112 	int64 frames;
1113 	media_decode_info info;
1114 	status_t result = fDecoder->Decode(fBuffer, &frames, header, &info);
1115 	if (result == B_OK) {
1116 		*chunkBuffer = fBuffer;
1117 		*chunkSize = frames * fFrameSize;
1118 //		printf("RawDecoderChunkProvider::GetNextChunk, %lld frames, "
1119 //			"%ld bytes, start-time %lld\n", frames, *chunkSize,
1120 //			header->start_time);
1121 	} else
1122 		ERROR("RawDecoderChunkProvider::GetNextChunk failed\n");
1123 
1124 	return result;
1125 }
1126