xref: /haiku/src/kits/media/MediaTrack.cpp (revision 218a8c03cbadd95d8888b218930f514fa0b4fac4)
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 
~BMediaTrack()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
InitCheck() const97 BMediaTrack::InitCheck() const
98 {
99 	CALLED();
100 
101 	return fInitStatus;
102 }
103 
104 
105 status_t
GetCodecInfo(media_codec_info * _codecInfo) const106 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
EncodedFormat(media_format * _format) const122 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 
DecodedFormat__11BMediaTrackP12media_format(BMediaTrack * self,media_format * _format)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
DecodedFormat(media_format * _format,uint32 flags)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
GetMetaData(BMessage * _data) const292 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 	return fExtractor->GetStreamMetaData(fStream, _data);
305 }
306 
307 
308 int64
CountFrames() const309 BMediaTrack::CountFrames() const
310 {
311 	CALLED();
312 
313 	int64 frames = fExtractor ? fExtractor->CountFrames(fStream) : 0;
314 //	printf("BMediaTrack::CountFrames: %lld\n", frames);
315 	return frames;
316 }
317 
318 
319 bigtime_t
Duration() const320 BMediaTrack::Duration() const
321 {
322 	CALLED();
323 
324 	bigtime_t duration = fExtractor ? fExtractor->Duration(fStream) : 0;
325 //	printf("BMediaTrack::Duration: %lld\n", duration);
326 	return duration;
327 }
328 
329 
330 int64
CurrentFrame() const331 BMediaTrack::CurrentFrame() const
332 {
333 	return fCurrentFrame;
334 }
335 
336 
337 bigtime_t
CurrentTime() const338 BMediaTrack::CurrentTime() const
339 {
340 	return fCurrentTime;
341 }
342 
343 // BMediaTrack::ReadFrames(char*, long long*, media_header*)
344 // Compatibility for R5 and below. Required by Corum III and Civ:CTP.
345 #if __GNUC__ < 3
346 
347 extern "C" status_t
ReadFrames__11BMediaTrackPcPxP12media_header(BMediaTrack * self,char * _buffer,int64 * _frameCount,media_header * header)348 ReadFrames__11BMediaTrackPcPxP12media_header(BMediaTrack* self,
349 	char* _buffer, int64* _frameCount, media_header* header)
350 {
351 	return self->ReadFrames(_buffer, _frameCount, header, 0);
352 }
353 
354 #endif	// __GNUC__ < 3
355 
356 status_t
ReadFrames(void * buffer,int64 * _frameCount,media_header * header)357 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount, media_header* header)
358 {
359 	return ReadFrames(buffer, _frameCount, header, NULL);
360 }
361 
362 
363 status_t
ReadFrames(void * buffer,int64 * _frameCount,media_header * _header,media_decode_info * info)364 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount,
365 	media_header* _header, media_decode_info* info)
366 {
367 //	CALLED();
368 
369 	if (fDecoder == NULL)
370 		return B_NO_INIT;
371 
372 	if (buffer == NULL || _frameCount == NULL)
373 		return B_BAD_VALUE;
374 
375 	media_header header;
376 	if (_header == NULL)
377 		_header = &header;
378 
379 	// Always clear the header first, as the decoder may not set all fields.
380 	memset(_header, 0, sizeof(media_header));
381 
382 	status_t result = fRawDecoder != NULL
383 		? fRawDecoder->Decode(buffer, _frameCount, _header, info)
384 		: fDecoder->Decode(buffer, _frameCount, _header, info);
385 
386 	if (result == B_OK) {
387 		fCurrentFrame += *_frameCount;
388 		bigtime_t framesDuration = (bigtime_t)(*_frameCount * 1000000
389 			/ _FrameRate());
390 		fCurrentTime = _header->start_time + framesDuration;
391 #if 0
392 	// This debug output shows drift between calculated fCurrentFrame and
393 	// time-based current frame, if there is any.
394 	if (fFormat.type == B_MEDIA_RAW_AUDIO) {
395 		printf("current frame: %lld / calculated: %lld (%.2f/%.2f)\r",
396 			fCurrentFrame,
397 			int64(fCurrentTime * _FrameRate() / 1000000.0 + 0.5),
398 			fCurrentTime / 1000000.0, (float)fCurrentFrame / _FrameRate());
399 		fflush(stdout);
400 	}
401 #endif
402 	} else {
403 		ERROR("BMediaTrack::ReadFrames: decoder returned error %#" B_PRIx32
404 			" (%s)\n", result, strerror(result));
405 		*_frameCount = 0;
406 	}
407 
408 #if 0
409 	PRINT(1, "BMediaTrack::ReadFrames: stream %ld, start-time %5Ld.%06Ld, "
410 		"%lld frames\n", fStream,  _header->start_time / 1000000,
411 		_header->start_time % 1000000, *out_frameCount);
412 #endif
413 
414 	return result;
415 }
416 
417 
418 status_t
ReplaceFrames(const void * inBuffer,int64 * _frameCount,const media_header * header)419 BMediaTrack::ReplaceFrames(const void* inBuffer, int64* _frameCount,
420 	const media_header* header)
421 {
422 	UNIMPLEMENTED();
423 
424 	// TODO: Actually, a file is either open for reading or writing at the
425 	// moment. Since the chunk size of encoded media data will change,
426 	// implementing this call will only be possible for raw media tracks.
427 
428 	return B_NOT_SUPPORTED;
429 }
430 
431 
432 status_t
SeekToTime(bigtime_t * _time,int32 flags)433 BMediaTrack::SeekToTime(bigtime_t* _time, int32 flags)
434 {
435 	CALLED();
436 
437 	if (fDecoder == NULL || fExtractor == NULL)
438 		return B_NO_INIT;
439 
440 	if (_time == NULL)
441 		return B_BAD_VALUE;
442 
443 	// Make sure flags are valid
444 	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME;
445 
446 	#if DEBUG
447 	bigtime_t requestedTime = *_time;
448 	#endif
449 	int64 frame = 0;
450 
451 	status_t result = fExtractor->Seek(fStream, flags, &frame, _time);
452 	if (result != B_OK) {
453 		ERROR("BMediaTrack::SeekToTime: extractor seek failed\n");
454 		return result;
455 	}
456 
457 	result = fDecoder->SeekedTo(frame, *_time);
458 	if (result != B_OK) {
459 		ERROR("BMediaTrack::SeekToTime: decoder seek failed\n");
460 		return result;
461 	}
462 
463 	if (fRawDecoder != NULL) {
464 		result = fRawDecoder->SeekedTo(frame, *_time);
465 		if (result != B_OK) {
466 			ERROR("BMediaTrack::SeekToTime: raw decoder seek failed\n");
467 			return result;
468 		}
469 	}
470 
471 	fCurrentFrame = frame;
472 	fCurrentTime = *_time;
473 
474 	PRINT(1, "BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n",
475 		requestedTime / 1000000.0, *_time / 1000000.0);
476 
477 	return B_OK;
478 }
479 
480 
481 status_t
SeekToFrame(int64 * _frame,int32 flags)482 BMediaTrack::SeekToFrame(int64* _frame, int32 flags)
483 {
484 	CALLED();
485 
486 	if (fDecoder == NULL || fExtractor == NULL)
487 		return B_NO_INIT;
488 
489 	if (_frame == NULL)
490 		return B_BAD_VALUE;
491 
492 	// Make sure flags are valid
493 	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_FRAME;
494 
495 	#if DEBUG
496 	int64 requestedFrame = *_frame;
497 	#endif
498 	bigtime_t time = 0;
499 
500 	status_t result = fExtractor->Seek(fStream, flags, _frame, &time);
501 	if (result != B_OK) {
502 		ERROR("BMediaTrack::SeekToFrame: extractor seek failed\n");
503 		return result;
504 	}
505 
506 	result = fDecoder->SeekedTo(*_frame, time);
507 	if (result != B_OK) {
508 		ERROR("BMediaTrack::SeekToFrame: decoder seek failed\n");
509 		return result;
510 	}
511 
512 	if (fRawDecoder != NULL) {
513 		result = fRawDecoder->SeekedTo(*_frame, time);
514 		if (result != B_OK) {
515 			ERROR("BMediaTrack::SeekToFrame: raw decoder seek failed\n");
516 			return result;
517 		}
518 	}
519 
520 	fCurrentFrame = *_frame;
521 	fCurrentTime = time;
522 
523 	PRINT(1, "BMediaTrack::SeekToTime SeekToFrame, requested %lld, "
524 		"result %lld\n", requestedFrame, *_frame);
525 
526 	return B_OK;
527 }
528 
529 
530 status_t
FindKeyFrameForTime(bigtime_t * _time,int32 flags) const531 BMediaTrack::FindKeyFrameForTime(bigtime_t* _time, int32 flags) const
532 {
533 	CALLED();
534 
535 	if (fExtractor == NULL)
536 		return B_NO_INIT;
537 
538 	if (_time == NULL)
539 		return B_BAD_VALUE;
540 
541 	// Make sure flags are valid
542 	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME;
543 
544 	int64 frame = 0;
545 		// dummy frame, will be ignored because of flags
546 	status_t result = fExtractor->FindKeyFrame(fStream, flags, &frame, _time);
547 	if (result != B_OK) {
548 		ERROR("BMediaTrack::FindKeyFrameForTime: extractor seek failed: %s\n",
549 			strerror(result));
550 	}
551 
552 	return result;
553 }
554 
555 
556 status_t
FindKeyFrameForFrame(int64 * _frame,int32 flags) const557 BMediaTrack::FindKeyFrameForFrame(int64* _frame, int32 flags) const
558 {
559 	CALLED();
560 
561 	if (fExtractor == NULL)
562 		return B_NO_INIT;
563 
564 	if (_frame == NULL)
565 		return B_BAD_VALUE;
566 
567 	// Make sure flags are valid
568 	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_FRAME;
569 
570 	bigtime_t time = 0;
571 		// dummy time, will be ignored because of flags
572 	status_t result = fExtractor->FindKeyFrame(fStream, flags, _frame, &time);
573 	if (result != B_OK) {
574 		ERROR("BMediaTrack::FindKeyFrameForFrame: extractor seek failed: %s\n",
575 			strerror(result));
576 	}
577 
578 	return result;
579 }
580 
581 
582 status_t
ReadChunk(char ** _buffer,int32 * _size,media_header * _header)583 BMediaTrack::ReadChunk(char** _buffer, int32* _size, media_header* _header)
584 {
585 	CALLED();
586 
587 	if (fExtractor == NULL)
588 		return B_NO_INIT;
589 
590 	if (_buffer == NULL || _size == NULL)
591 		return B_BAD_VALUE;
592 
593 	media_header header;
594 	if (_header == NULL)
595 		_header = &header;
596 
597 	// Always clear the header first, as the extractor may not set all fields.
598 	memset(_header, 0, sizeof(media_header));
599 
600 	const void* buffer;
601 	size_t size;
602 	status_t result = fExtractor->GetNextChunk(fStream, &buffer, &size,
603 		_header);
604 
605 	if (result == B_OK) {
606 		*_buffer = const_cast<char*>(static_cast<const char*>(buffer));
607 			// TODO: Change the pointer type when we break the API.
608 		*_size = size;
609 		// TODO: This changes the meaning of fCurrentTime from pointing
610 		// to the next chunk start time (i.e. after seeking) to the start time
611 		// of the last chunk. Asking the extractor for the current time will
612 		// not work so well because of the chunk cache. But providing a
613 		// "duration" field in the media_header could be useful.
614 		fCurrentTime = _header->start_time;
615 		fCurrentFrame = (int64)(fCurrentTime * _FrameRate() / 1000000LL);
616 
617 	}
618 
619 	return result;
620 }
621 
622 
623 status_t
AddCopyright(const char * copyright)624 BMediaTrack::AddCopyright(const char* copyright)
625 {
626 	if (fWriter == NULL)
627 		return B_NO_INIT;
628 
629 	return fWriter->SetCopyright(fStream, copyright);
630 }
631 
632 
633 status_t
AddTrackInfo(uint32 code,const void * data,size_t size,uint32 flags)634 BMediaTrack::AddTrackInfo(uint32 code, const void* data, size_t size,
635 	uint32 flags)
636 {
637 	if (fWriter == NULL)
638 		return B_NO_INIT;
639 
640 	return fWriter->AddTrackInfo(fStream, code, data, size, flags);
641 }
642 
643 
644 status_t
WriteFrames(const void * data,int32 frameCount,int32 flags)645 BMediaTrack::WriteFrames(const void* data, int32 frameCount, int32 flags)
646 {
647 	media_encode_info encodeInfo;
648 	encodeInfo.flags = flags;
649 
650 	return WriteFrames(data, frameCount, &encodeInfo);
651 }
652 
653 
654 status_t
WriteFrames(const void * data,int64 frameCount,media_encode_info * info)655 BMediaTrack::WriteFrames(const void* data, int64 frameCount,
656 	media_encode_info* info)
657 {
658 	if (fEncoder == NULL)
659 		return B_NO_INIT;
660 
661 	return fEncoder->Encode(data, frameCount, info);
662 }
663 
664 
665 status_t
WriteChunk(const void * data,size_t size,uint32 flags)666 BMediaTrack::WriteChunk(const void* data, size_t size, uint32 flags)
667 {
668 	media_encode_info encodeInfo;
669 	encodeInfo.flags = flags;
670 
671 	return WriteChunk(data, size, &encodeInfo);
672 }
673 
674 
675 status_t
WriteChunk(const void * data,size_t size,media_encode_info * info)676 BMediaTrack::WriteChunk(const void* data, size_t size, media_encode_info* info)
677 {
678 	if (fWriter == NULL)
679 		return B_NO_INIT;
680 
681 	return fWriter->WriteChunk(fStream, data, size, info);
682 }
683 
684 
685 status_t
Flush()686 BMediaTrack::Flush()
687 {
688 	if (fWriter == NULL)
689 		return B_NO_INIT;
690 
691 	return fWriter->Flush();
692 }
693 
694 
695 // deprecated BeOS R5 API
696 BParameterWeb*
Web()697 BMediaTrack::Web()
698 {
699 	BParameterWeb* web;
700 	if (GetParameterWeb(&web) == B_OK)
701 		return web;
702 
703 	return NULL;
704 }
705 
706 
707 status_t
GetParameterWeb(BParameterWeb ** outWeb)708 BMediaTrack::GetParameterWeb(BParameterWeb** outWeb)
709 {
710 	if (outWeb == NULL)
711 		return B_BAD_VALUE;
712 
713 	if (fEncoder == NULL)
714 		return B_NO_INIT;
715 
716 	// TODO: This method is new in Haiku. The header mentions it returns a
717 	// copy. But how could it even do that? How can one clone a web and make
718 	// it point to the same BControllable?
719 	*outWeb = fEncoder->ParameterWeb();
720 	if (*outWeb != NULL)
721 		return B_OK;
722 
723 	return B_NOT_SUPPORTED;
724 }
725 
726 
727 status_t
GetParameterValue(int32 id,void * value,size_t * size)728 BMediaTrack::GetParameterValue(int32 id, void* value, size_t* size)
729 {
730 	if (value == NULL || size == NULL)
731 		return B_BAD_VALUE;
732 
733 	if (fEncoder == NULL)
734 		return B_NO_INIT;
735 
736 	return fEncoder->GetParameterValue(id, value, size);
737 }
738 
739 
740 status_t
SetParameterValue(int32 id,const void * value,size_t size)741 BMediaTrack::SetParameterValue(int32 id, const void* value, size_t size)
742 {
743 	if (value == NULL || size == 0)
744 		return B_BAD_VALUE;
745 
746 	if (fEncoder == NULL)
747 		return B_NO_INIT;
748 
749 	return fEncoder->SetParameterValue(id, value, size);
750 }
751 
752 
753 BView*
GetParameterView()754 BMediaTrack::GetParameterView()
755 {
756 	if (fEncoder == NULL)
757 		return NULL;
758 
759 	return fEncoder->ParameterView();
760 }
761 
762 
763 status_t
GetQuality(float * quality)764 BMediaTrack::GetQuality(float* quality)
765 {
766 	if (quality == NULL)
767 		return B_BAD_VALUE;
768 
769 	encode_parameters parameters;
770 	status_t result = GetEncodeParameters(&parameters);
771 	if (result != B_OK)
772 		return result;
773 
774 	*quality = parameters.quality;
775 
776 	return B_OK;
777 }
778 
779 
780 status_t
SetQuality(float quality)781 BMediaTrack::SetQuality(float quality)
782 {
783 	encode_parameters parameters;
784 	status_t result = GetEncodeParameters(&parameters);
785 	if (result != B_OK)
786 		return result;
787 
788 	if (quality < 0.0f)
789 		quality = 0.0f;
790 
791 	if (quality > 1.0f)
792 		quality = 1.0f;
793 
794 	parameters.quality = quality;
795 
796 	return SetEncodeParameters(&parameters);
797 }
798 
799 
800 status_t
GetEncodeParameters(encode_parameters * parameters) const801 BMediaTrack::GetEncodeParameters(encode_parameters* parameters) const
802 {
803 	if (parameters == NULL)
804 		return B_BAD_VALUE;
805 
806 	if (fEncoder == NULL)
807 		return B_NO_INIT;
808 
809 	return fEncoder->GetEncodeParameters(parameters);
810 }
811 
812 
813 status_t
SetEncodeParameters(encode_parameters * parameters)814 BMediaTrack::SetEncodeParameters(encode_parameters* parameters)
815 {
816 	if (parameters == NULL)
817 		return B_BAD_VALUE;
818 
819 	if (fEncoder == NULL)
820 		return B_NO_INIT;
821 
822 	return fEncoder->SetEncodeParameters(parameters);
823 }
824 
825 
826 status_t
Perform(int32 selector,void * data)827 BMediaTrack::Perform(int32 selector, void* data)
828 {
829 	return B_OK;
830 }
831 
832 // #pragma mark - private
833 
834 
BMediaTrack(BPrivate::media::MediaExtractor * extractor,int32 stream)835 BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor* extractor,
836 	int32 stream)
837 {
838 	CALLED();
839 
840 	fWorkaroundFlags = 0;
841 	fDecoder = NULL;
842 	fRawDecoder = NULL;
843 	fExtractor = extractor;
844 	fStream = stream;
845 	fInitStatus = B_OK;
846 
847 	SetupWorkaround();
848 
849 	status_t ret = fExtractor->CreateDecoder(fStream, &fDecoder, &fCodecInfo);
850 	if (ret != B_OK) {
851 		TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
852 			"%s\n", strerror(ret));
853 		// We do not set fInitStatus here, because ReadChunk should still work.
854 		fDecoder = NULL;
855 	}
856 
857 	fCurrentFrame = 0;
858 	fCurrentTime = 0;
859 
860 	// not used:
861 	fEncoder = NULL;
862 	fEncoderID = 0;
863 	fWriter = NULL;
864 }
865 
866 
BMediaTrack(BPrivate::media::MediaWriter * writer,int32 streamIndex,media_format * format,const media_codec_info * codecInfo)867 BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
868 	int32 streamIndex, media_format* format,
869 	const media_codec_info* codecInfo)
870 {
871 	CALLED();
872 
873 	fWorkaroundFlags = 0;
874 	fEncoder = NULL;
875 	fEncoderID = -1;
876 		// TODO: Not yet sure what this was needed for...
877 	fWriter = writer;
878 	fStream = streamIndex;
879 	fInitStatus = B_OK;
880 
881 	SetupWorkaround();
882 
883 	if (codecInfo != NULL) {
884 		status_t ret = fWriter->CreateEncoder(&fEncoder, codecInfo, format);
885 		if (ret != B_OK) {
886 			TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
887 				"%s\n", strerror(ret));
888 			// We do not set fInitStatus here, because WriteChunk should still
889 			// work.
890 			fEncoder = NULL;
891 		} else {
892 			fCodecInfo = *codecInfo;
893 			fInitStatus = fEncoder->SetUp(format);
894 		}
895 	}
896 
897 	fFormat = *format;
898 
899 	// not used:
900 	fCurrentFrame = 0;
901 	fCurrentTime = 0;
902 	fDecoder = NULL;
903 	fRawDecoder = NULL;
904 	fExtractor = NULL;
905 }
906 
907 
908 // Does nothing, returns B_ERROR, for Zeta compatiblity only
909 status_t
ControlCodec(int32 selector,void * io_data,size_t size)910 BMediaTrack::ControlCodec(int32 selector, void* io_data, size_t size)
911 {
912 	return B_ERROR;
913 }
914 
915 
916 void
SetupWorkaround()917 BMediaTrack::SetupWorkaround()
918 {
919 	app_info	ainfo;
920 	thread_info	tinfo;
921 
922 	get_thread_info(find_thread(0), &tinfo);
923 	be_roster->GetRunningAppInfo(tinfo.team, &ainfo);
924 
925 	if (strcmp(ainfo.signature, "application/x-vnd.marcone-soundplay") == 0) {
926 		fWorkaroundFlags = FORCE_RAW_AUDIO | FORCE_RAW_AUDIO_INT16_FORMAT
927 			| FORCE_RAW_AUDIO_HOST_ENDIAN;
928 		printf("BMediaTrack::SetupWorkaround: SoundPlay workaround active\n");
929 	}
930 	if (strcmp(ainfo.signature, "application/x-vnd.Be.MediaPlayer") == 0) {
931 		fWorkaroundFlags = IGNORE_ENCODED_AUDIO | IGNORE_ENCODED_VIDEO;
932 		printf("BMediaTrack::SetupWorkaround: MediaPlayer workaround active\n");
933 	}
934 
935 #if CONVERT_TO_INT32
936 	// TODO: Test
937 	if (!(fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT))
938 		fWorkaroundFlags |= FORCE_RAW_AUDIO_INT32_FORMAT;
939 #endif
940 }
941 
942 
943 bool
SetupFormatTranslation(const media_format & from,media_format * to)944 BMediaTrack::SetupFormatTranslation(const media_format &from, media_format* to)
945 {
946 	gPluginManager.DestroyDecoder(fRawDecoder);
947 	fRawDecoder = NULL;
948 
949 #ifdef TRACE_MEDIA_TRACK
950 	char s[200];
951 	string_for_format(from, s, sizeof(s));
952 	printf("BMediaTrack::SetupFormatTranslation: from: %s\n", s);
953 #endif
954 
955 	status_t result = gPluginManager.CreateDecoder(&fRawDecoder, from);
956 	if (result != B_OK) {
957 		ERROR("BMediaTrack::SetupFormatTranslation: CreateDecoder failed\n");
958 		return false;
959 	}
960 
961 	// XXX video?
962 	int buffer_size = from.u.raw_audio.buffer_size;
963 	int frame_size = (from.u.raw_audio.format & 15)
964 		* from.u.raw_audio.channel_count;
965 	media_format fromNotConst = from;
966 
967 	ChunkProvider* chunkProvider
968 		= new (std::nothrow) RawDecoderChunkProvider(fDecoder, buffer_size,
969 			frame_size);
970 	if (chunkProvider == NULL) {
971 		ERROR("BMediaTrack::SetupFormatTranslation: can't create chunk "
972 			"provider\n");
973 		goto error;
974 	}
975 	fRawDecoder->SetChunkProvider(chunkProvider);
976 
977 	result = fRawDecoder->Setup(&fromNotConst, 0, 0);
978 	if (result != B_OK) {
979 		ERROR("BMediaTrack::SetupFormatTranslation: Setup failed\n");
980 		goto error;
981 	}
982 
983 #ifdef TRACE_MEDIA_TRACK
984 	string_for_format(*to, s, sizeof(s));
985 	printf("BMediaTrack::SetupFormatTranslation:   to: %s\n", s);
986 #endif
987 
988 	result = fRawDecoder->NegotiateOutputFormat(to);
989 	if (result != B_OK) {
990 		ERROR("BMediaTrack::SetupFormatTranslation: NegotiateOutputFormat "
991 			"failed\n");
992 		goto error;
993 	}
994 
995 #ifdef TRACE_MEDIA_TRACK
996 	string_for_format(*to, s, sizeof(s));
997 	printf("BMediaTrack::SetupFormatTranslation:  result: %s\n", s);
998 #endif
999 
1000 	return true;
1001 
1002 error:
1003 	gPluginManager.DestroyDecoder(fRawDecoder);
1004 	fRawDecoder = NULL;
1005 	return false;
1006 }
1007 
1008 
1009 double
_FrameRate() const1010 BMediaTrack::_FrameRate() const
1011 {
1012 	switch (fFormat.type) {
1013 		case B_MEDIA_RAW_VIDEO:
1014 			return fFormat.u.raw_video.field_rate;
1015 		case B_MEDIA_ENCODED_VIDEO:
1016 			return fFormat.u.encoded_video.output.field_rate;
1017 		case B_MEDIA_RAW_AUDIO:
1018 			return fFormat.u.raw_audio.frame_rate;
1019 		case B_MEDIA_ENCODED_AUDIO:
1020 			return fFormat.u.encoded_audio.output.frame_rate;
1021 		default:
1022 			return 1.0;
1023 	}
1024 }
1025 
1026 #if 0
1027 // unimplemented
1028 BMediaTrack::BMediaTrack()
1029 BMediaTrack::BMediaTrack(const BMediaTrack &)
1030 BMediaTrack &BMediaTrack::operator=(const BMediaTrack &)
1031 #endif
1032 
_Reserved_BMediaTrack_0(int32 arg,...)1033 status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_1(int32 arg,...)1034 status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_2(int32 arg,...)1035 status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_3(int32 arg,...)1036 status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_4(int32 arg,...)1037 status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_5(int32 arg,...)1038 status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_6(int32 arg,...)1039 status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_7(int32 arg,...)1040 status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_8(int32 arg,...)1041 status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_9(int32 arg,...)1042 status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_10(int32 arg,...)1043 status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_11(int32 arg,...)1044 status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_12(int32 arg,...)1045 status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_13(int32 arg,...)1046 status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_14(int32 arg,...)1047 status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_15(int32 arg,...)1048 status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_16(int32 arg,...)1049 status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_17(int32 arg,...)1050 status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_18(int32 arg,...)1051 status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_19(int32 arg,...)1052 status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_20(int32 arg,...)1053 status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_21(int32 arg,...)1054 status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_22(int32 arg,...)1055 status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_23(int32 arg,...)1056 status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_24(int32 arg,...)1057 status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_25(int32 arg,...)1058 status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_26(int32 arg,...)1059 status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_27(int32 arg,...)1060 status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_28(int32 arg,...)1061 status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_29(int32 arg,...)1062 status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_30(int32 arg,...)1063 status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_31(int32 arg,...)1064 status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_32(int32 arg,...)1065 status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_33(int32 arg,...)1066 status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_34(int32 arg,...)1067 status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_35(int32 arg,...)1068 status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_36(int32 arg,...)1069 status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_37(int32 arg,...)1070 status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_38(int32 arg,...)1071 status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_39(int32 arg,...)1072 status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_40(int32 arg,...)1073 status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_41(int32 arg,...)1074 status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_42(int32 arg,...)1075 status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_43(int32 arg,...)1076 status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_44(int32 arg,...)1077 status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_45(int32 arg,...)1078 status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_46(int32 arg,...)1079 status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; }
_Reserved_BMediaTrack_47(int32 arg,...)1080 status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; }
1081 
1082 
RawDecoderChunkProvider(Decoder * decoder,int buffer_size,int frame_size)1083 RawDecoderChunkProvider::RawDecoderChunkProvider(Decoder* decoder,
1084 	int buffer_size, int frame_size)
1085 {
1086 //	printf("RawDecoderChunkProvider: buffer_size %d, frame_size %d\n",
1087 //		buffer_size, frame_size);
1088 	fDecoder = decoder;
1089 	fFrameSize = frame_size;
1090 	fBufferSize = buffer_size;
1091 	fBuffer = malloc(buffer_size);
1092 }
1093 
1094 
~RawDecoderChunkProvider()1095 RawDecoderChunkProvider::~RawDecoderChunkProvider()
1096 {
1097 	free(fBuffer);
1098 }
1099 
1100 
1101 status_t
GetNextChunk(const void ** chunkBuffer,size_t * chunkSize,media_header * header)1102 RawDecoderChunkProvider::GetNextChunk(const void** chunkBuffer,
1103 	size_t* chunkSize, media_header* header)
1104 {
1105 	int64 frames;
1106 	media_decode_info info;
1107 	status_t result = fDecoder->Decode(fBuffer, &frames, header, &info);
1108 	if (result == B_OK) {
1109 		*chunkBuffer = fBuffer;
1110 		*chunkSize = frames * fFrameSize;
1111 //		printf("RawDecoderChunkProvider::GetNextChunk, %lld frames, "
1112 //			"%ld bytes, start-time %lld\n", frames, *chunkSize,
1113 //			header->start_time);
1114 	} else
1115 		ERROR("RawDecoderChunkProvider::GetNextChunk failed\n");
1116 
1117 	return result;
1118 }
1119