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