3rdparty/licenseReport: Add seperate LGPL checks
[haiku.git] / src / add-ons / media / plugins / asf_reader / asf_reader.cpp
bloba0557b0ac560845bb4a8c3694eff1873c30ed43a
1 /*
2 * Copyright (c) 2005, David McPaul based on avi_reader copyright (c) 2004 Marcus Overhagen
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
23 * OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "asf_reader.h"
28 #include "RawFormats.h"
30 #include <ByteOrder.h>
31 #include <DataIO.h>
32 #include <InterfaceDefs.h>
33 #include <MediaFormats.h>
34 #include <StopWatch.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
41 #define TRACE_ASF_READER
42 #ifdef TRACE_ASF_READER
43 # define TRACE printf
44 #else
45 # define TRACE(a...)
46 #endif
48 #define ERROR(a...) fprintf(stderr, a)
50 struct asf_cookie {
51 unsigned stream;
52 char * buffer;
53 unsigned buffer_size;
55 int64 frame_count;
56 bigtime_t duration;
57 media_format format;
59 bool audio;
61 // audio only:
62 uint32 bytes_per_sec_rate;
63 uint32 bytes_per_sec_scale;
65 // video only:
66 uint32 line_count;
68 // Common
69 uint32 frame_pos;
70 uint32 frames_per_sec_rate;
71 uint32 frames_per_sec_scale;
72 uint32 frame_size;
75 asfReader::asfReader()
76 : theFileReader(0)
78 TRACE("asfReader::asfReader\n");
82 asfReader::~asfReader()
84 delete theFileReader;
88 const char *
89 asfReader::Copyright()
91 return "asf_reader " B_UTF8_COPYRIGHT " by David McPaul";
95 status_t
96 asfReader::Sniff(int32 *streamCount)
98 TRACE("asfReader::Sniff\n");
100 BPositionIO *pos_io_source;
102 pos_io_source = dynamic_cast<BPositionIO *>(Reader::Source());
103 if (!pos_io_source) {
104 TRACE("asfReader::Sniff: not a BPositionIO\n");
105 return B_ERROR;
108 if (!ASFFileReader::IsSupported(pos_io_source)) {
109 TRACE("asfReader::Sniff: unsupported file type\n");
110 return B_ERROR;
113 TRACE("asfReader::Sniff: this stream seems to be supported\n");
115 theFileReader = new ASFFileReader(pos_io_source);
116 if (B_OK != theFileReader->ParseFile()) {
117 ERROR("asfReader::Sniff: error parsing file\n");
118 return B_ERROR;
121 *streamCount = theFileReader->getStreamCount();
123 TRACE("asfReader detected %ld streams\n",*streamCount);
124 return B_OK;
128 void
129 asfReader::GetFileFormatInfo(media_file_format *mff)
131 mff->capabilities = media_file_format::B_READABLE
132 | media_file_format::B_KNOWS_ENCODED_VIDEO
133 | media_file_format::B_KNOWS_ENCODED_AUDIO
134 | media_file_format::B_IMPERFECTLY_SEEKABLE;
135 mff->family = B_MISC_FORMAT_FAMILY;
136 mff->version = 100;
137 strcpy(mff->mime_type, "video/asf");
138 strcpy(mff->file_extension, "asf");
139 strcpy(mff->short_name, "ASF");
140 strcpy(mff->pretty_name, "Microsoft (ASF) file format");
143 status_t
144 asfReader::AllocateCookie(int32 streamNumber, void **_cookie)
146 uint32 codecID = 0;
148 size_t size;
149 const void *data;
151 asf_cookie *cookie = new asf_cookie;
152 *_cookie = cookie;
154 cookie->stream = streamNumber;
155 cookie->buffer = 0;
156 cookie->buffer_size = 0;
157 cookie->frame_pos = 0;
159 BMediaFormats formats;
160 media_format *format = &cookie->format;
161 media_format_description description;
163 ASFAudioFormat audioFormat;
164 ASFVideoFormat videoFormat;
166 if (theFileReader->getVideoFormat(streamNumber,&videoFormat)) {
167 TRACE("Stream %ld is Video\n",streamNumber);
168 char cc1,cc2,cc3,cc4;
170 cc1 = (char)((videoFormat.Compression >> 24) & 0xff);
171 cc2 = (char)((videoFormat.Compression >> 16) & 0xff);
172 cc3 = (char)((videoFormat.Compression >> 8) & 0xff);
173 cc4 = (char)((videoFormat.Compression >> 0) & 0xff);
175 TRACE("Compression %c%c%c%c\n", cc1,cc2,cc3,cc4);
177 TRACE("Width %ld\n",videoFormat.VideoWidth);
178 TRACE("Height %ld\n",videoFormat.VideoHeight);
179 TRACE("Planes %d\n",videoFormat.Planes);
180 TRACE("BitCount %d\n",videoFormat.BitCount);
182 codecID = B_BENDIAN_TO_HOST_INT32(videoFormat.Compression);
184 cookie->audio = false;
185 cookie->line_count = videoFormat.VideoHeight;
186 cookie->frame_size = 1;
188 cookie->duration = theFileReader->getStreamDuration(streamNumber);
189 cookie->frame_count = theFileReader->getFrameCount(streamNumber);
191 TRACE("frame_count %Ld\n", cookie->frame_count);
192 TRACE("duration %.6f (%Ld)\n", cookie->duration / 1E6, cookie->duration);
193 TRACE("calculated fps=%Ld\n", cookie->frame_count * 1000000LL / cookie->duration);
195 // asf does not have a frame rate! The extended descriptor defines an average time per frame which is generally useless.
196 if (videoFormat.FrameScale && videoFormat.FrameRate) {
197 cookie->frames_per_sec_rate = videoFormat.FrameRate;
198 cookie->frames_per_sec_scale = videoFormat.FrameScale;
199 TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using average time per frame)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
200 } else {
201 cookie->frames_per_sec_rate = cookie->frame_count;
202 cookie->frames_per_sec_scale = cookie->duration / 1000000LL;
203 TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (duration over frame count)\n", cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
206 description.family = B_AVI_FORMAT_FAMILY;
207 description.u.avi.codec = videoFormat.Compression;
209 if (B_OK != formats.GetFormatFor(description, format))
210 format->type = B_MEDIA_ENCODED_VIDEO;
212 // Can we just define a set of bitrates instead of a field rate?
213 // format->u.encoded_video.max_bit_rate = 8 * theFileReader->MovMainHeader()->max_bytes_per_sec;
214 // format->u.encoded_video.avg_bit_rate = format->u.encoded_video.max_bit_rate / 2; // XXX fix this
215 format->u.encoded_video.output.field_rate = cookie->frames_per_sec_rate / (float)cookie->frames_per_sec_scale;
217 format->u.encoded_video.avg_bit_rate = 1;
218 format->u.encoded_video.max_bit_rate = 1;
220 format->u.encoded_video.frame_size = videoFormat.VideoWidth * videoFormat.VideoHeight * videoFormat.Planes / 8;
221 format->u.encoded_video.output.display.bytes_per_row = videoFormat.Planes / 8 * videoFormat.VideoWidth;
222 // align to 2 bytes
223 format->u.encoded_video.output.display.bytes_per_row += format->u.encoded_video.output.display.bytes_per_row & 1;
225 switch (videoFormat.BitCount) {
226 case 16:
227 format->u.encoded_video.output.display.format = B_RGB15_BIG;
228 break;
229 case 24:
230 format->u.encoded_video.output.display.format = B_RGB24_BIG;
231 break;
232 case 32:
233 format->u.encoded_video.output.display.format = B_RGB32_BIG;
234 break;
235 default:
236 format->u.encoded_video.output.display.format = B_NO_COLOR_SPACE;
237 format->u.encoded_video.frame_size = videoFormat.VideoWidth * videoFormat.VideoHeight * 8 / 8;
240 format->u.encoded_video.output.display.line_width = videoFormat.VideoWidth;
241 format->u.encoded_video.output.display.line_count = videoFormat.VideoHeight;
242 format->u.encoded_video.output.display.pixel_offset = 0;
243 format->u.encoded_video.output.display.line_offset = 0;
244 format->u.encoded_video.output.display.flags = 0;
245 format->u.encoded_video.output.interlace = 1; // 1: progressive
246 format->u.encoded_video.output.first_active = 0;
247 format->u.encoded_video.output.last_active = format->u.encoded_video.output.display.line_count - 1;
248 format->u.encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT;
249 format->u.encoded_video.output.pixel_width_aspect = 1;
250 format->u.encoded_video.output.pixel_height_aspect = 1;
252 TRACE("max_bit_rate %.3f\n", format->u.encoded_video.max_bit_rate);
253 TRACE("field_rate %.3f\n", format->u.encoded_video.output.field_rate);
255 // Set the Decoder Config
256 size = videoFormat.extraDataSize;
257 data = videoFormat.extraData;
258 if (size > 0) {
259 TRACE("Video Decoder Config Found Size is %ld\n",size);
260 if (format->SetMetaData(data, size) != B_OK) {
261 ERROR("Failed to set Decoder Config\n");
262 delete cookie;
263 return B_ERROR;
266 #ifdef TRACE_ASF_READER
267 if (videoFormat.extraData) {
268 uint8 *p = (uint8 *)videoFormat.extraData;
269 TRACE("extra_data: %ld: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
270 size, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
272 #endif
275 if (codecID != 0) {
276 // Put the codeid in the user data in case someone wants it
277 format->user_data_type = B_CODEC_TYPE_INFO;
278 *(uint32 *)format->user_data = codecID; format->user_data[4] = 0;
281 cookie->buffer_size = ((videoFormat.VideoWidth * videoFormat.VideoHeight * 4) + 15) & ~15; // WRONG Find max input buffer size needed
282 cookie->buffer = new char [cookie->buffer_size];
284 return B_OK;
288 if (theFileReader->getAudioFormat(streamNumber,&audioFormat)) {
289 TRACE("Stream %ld is Audio\n",streamNumber);
290 TRACE("Format 0x%x\n",audioFormat.Compression);
291 TRACE("Channels %d\n",audioFormat.NoChannels);
292 TRACE("SampleRate %ld\n",audioFormat.SamplesPerSec);
293 TRACE("ByteRate %ld\n",audioFormat.AvgBytesPerSec);
294 TRACE("BlockAlign %d\n",audioFormat.BlockAlign);
295 TRACE("Bits %d\n",audioFormat.BitsPerSample);
297 //uint32 sampleSize = (audioFormat.NoChannels * audioFormat.BitsPerSample / 8);
299 cookie->audio = true;
300 cookie->duration = theFileReader->getStreamDuration(streamNumber);
301 // Calculate sample count using duration
302 cookie->frame_count = (cookie->duration * audioFormat.SamplesPerSec) / 1000000LL;
303 cookie->frame_pos = 0;
304 cookie->frames_per_sec_rate = audioFormat.SamplesPerSec;
305 cookie->frames_per_sec_scale = 1;
306 cookie->bytes_per_sec_rate = audioFormat.AvgBytesPerSec;
307 cookie->bytes_per_sec_scale = 1;
309 TRACE("Chunk Count %ld\n", theFileReader->getFrameCount(streamNumber));
310 TRACE("audio frame_count %Ld, duration %.6f\n", cookie->frame_count, cookie->duration / 1E6 );
312 if (audioFormat.Compression == 0x0001) {
313 // a raw PCM format
314 description.family = B_BEOS_FORMAT_FAMILY;
315 description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
316 if (formats.GetFormatFor(description, format) < B_OK)
317 format->type = B_MEDIA_RAW_AUDIO;
318 format->u.raw_audio.frame_rate = audioFormat.SamplesPerSec;
319 format->u.raw_audio.channel_count = audioFormat.NoChannels;
320 if (audioFormat.BitsPerSample <= 8)
321 format->u.raw_audio.format = B_AUDIO_FORMAT_UINT8;
322 else if (audioFormat.BitsPerSample <= 16)
323 format->u.raw_audio.format = B_AUDIO_FORMAT_INT16;
324 else if (audioFormat.BitsPerSample <= 24)
325 format->u.raw_audio.format = B_AUDIO_FORMAT_INT24;
326 else if (audioFormat.BitsPerSample <= 32)
327 format->u.raw_audio.format = B_AUDIO_FORMAT_INT32;
328 else {
329 ERROR("asfReader::AllocateCookie: unhandled bits per sample %d\n", audioFormat.BitsPerSample);
330 return B_ERROR;
332 format->u.raw_audio.format |= B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE;
333 format->u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN;
334 format->u.raw_audio.buffer_size = audioFormat.BlockAlign;
335 } else if (audioFormat.Compression == 0xa) {
336 // Windows Media Speech
337 return B_ERROR;
338 } else {
339 // some encoded format
340 description.family = B_WAV_FORMAT_FAMILY;
341 description.u.wav.codec = audioFormat.Compression;
342 if (formats.GetFormatFor(description, format) < B_OK)
343 format->type = B_MEDIA_ENCODED_AUDIO;
344 format->u.encoded_audio.bit_rate = 8 * audioFormat.AvgBytesPerSec;
345 format->u.encoded_audio.output.frame_rate = audioFormat.SamplesPerSec;
346 format->u.encoded_audio.output.channel_count = audioFormat.NoChannels;
347 format->u.encoded_audio.output.buffer_size = audioFormat.BlockAlign;
348 cookie->frame_size = audioFormat.BlockAlign == 0 ? 1 : audioFormat.BlockAlign;
350 TRACE("audio: bit_rate %.3f, frame_rate %.1f, channel_count %lu, frame_size %ld\n",
351 format->u.encoded_audio.bit_rate,
352 format->u.encoded_audio.output.frame_rate,
353 format->u.encoded_audio.output.channel_count,
354 cookie->frame_size);
357 cookie->buffer_size = (audioFormat.BlockAlign + 15) & ~15;
358 cookie->buffer = new char [cookie->buffer_size];
360 // TODO: this doesn't seem to work (it's not even a fourcc)
361 format->user_data_type = B_CODEC_TYPE_INFO;
362 *(uint32 *)format->user_data = audioFormat.Compression; format->user_data[4] = 0;
364 // Set the Decoder Config
365 size = audioFormat.extraDataSize;
366 data = audioFormat.extraData;
367 if (size > 0) {
368 TRACE("Audio Decoder Config Found Size is %ld\n",size);
369 if (format->SetMetaData(data, size) != B_OK) {
370 ERROR("Failed to set Decoder Config\n");
371 delete cookie;
372 return B_ERROR;
375 #ifdef TRACE_ASF_READER
376 if (audioFormat.extraData) {
377 uint8 *p = (uint8 *)audioFormat.extraData;
378 TRACE("extra_data: %ld: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
379 size, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
381 #endif
384 return B_OK;
388 delete cookie;
389 return B_ERROR;
393 status_t
394 asfReader::FreeCookie(void *_cookie)
396 asf_cookie *cookie = (asf_cookie *)_cookie;
398 delete [] cookie->buffer;
400 delete cookie;
401 return B_OK;
405 status_t
406 asfReader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration,
407 media_format *format, const void **infoBuffer, size_t *infoSize)
409 asf_cookie *cookie = (asf_cookie *)_cookie;
410 ASFAudioFormat audioFormat;
411 ASFVideoFormat videoFormat;
413 if (cookie) {
414 *frameCount = cookie->frame_count;
415 *duration = cookie->duration;
416 *format = cookie->format;
418 *infoSize = 0;
420 // Copy metadata to infoBuffer
421 if (theFileReader->getVideoFormat(cookie->stream,&videoFormat)) {
422 *infoSize = videoFormat.extraDataSize;
423 *infoBuffer = videoFormat.extraData;
424 } else if (theFileReader->getAudioFormat(cookie->stream,&audioFormat)) {
425 *infoSize = audioFormat.extraDataSize;
426 *infoBuffer = audioFormat.extraData;
427 } else {
428 ERROR("No stream Info for stream %d\n",cookie->stream);
431 TRACE("GetStreamInfo (%d) fc %Ld duration %Ld extra %ld\n",cookie->stream,*frameCount,*duration,*infoSize);
433 return B_OK;
437 status_t
438 asfReader::Seek(void *cookie, uint32 flags, int64 *frame, bigtime_t *time)
440 // seek to the requested time or frame
441 asf_cookie *asfCookie = (asf_cookie *)cookie;
443 if (flags & B_MEDIA_SEEK_TO_TIME) {
444 // frame = (time * rate) / fps / 1000000LL
445 *frame = ((*time * asfCookie->frames_per_sec_rate) / (int64)asfCookie->frames_per_sec_scale) / 1000000LL;
446 asfCookie->frame_pos = theFileReader->GetFrameForTime(asfCookie->stream,*time);
449 if (flags & B_MEDIA_SEEK_TO_FRAME) {
450 // time = frame * 1000000LL * fps / rate
451 *time = (*frame * 1000000LL * (int64)asfCookie->frames_per_sec_scale) / asfCookie->frames_per_sec_rate;
452 asfCookie->frame_pos = theFileReader->GetFrameForTime(asfCookie->stream,*time);
455 TRACE("asfReader::Seek: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
456 (flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
457 (flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
458 (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
459 (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
460 *time, *frame);
462 return B_OK;
465 status_t
466 asfReader::FindKeyFrame(void* cookie, uint32 flags,
467 int64* frame, bigtime_t* time)
469 // Find the nearest keyframe to the given time or frame.
471 asf_cookie *asfCookie = (asf_cookie *)cookie;
472 IndexEntry indexEntry;
474 if (flags & B_MEDIA_SEEK_TO_TIME) {
475 // convert time to frame as we seek by frame
476 // frame = (time * rate) / fps / 1000000LL
477 *frame = ((*time * asfCookie->frames_per_sec_rate) / (int64)asfCookie->frames_per_sec_scale) / 1000000LL;
480 TRACE("asfReader::FindKeyFrame: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
481 (flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
482 (flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
483 (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
484 (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
485 *time, *frame);
487 if (asfCookie->audio == false) {
488 // Only video has keyframes
489 if (flags & B_MEDIA_SEEK_CLOSEST_FORWARD || flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) {
490 indexEntry = theFileReader->GetIndex(asfCookie->stream,*frame);
492 while (indexEntry.noPayloads > 0 && indexEntry.keyFrame == false && *frame > 0) {
493 if (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) {
494 (*frame)--;
495 } else {
496 (*frame)++;
498 indexEntry = theFileReader->GetIndex(asfCookie->stream,*frame);
501 if (indexEntry.noPayloads == 0) {
502 return B_ERROR;
507 *time = *frame * 1000000LL * (int64)asfCookie->frames_per_sec_scale / asfCookie->frames_per_sec_rate;
509 return B_OK;
512 status_t
513 asfReader::GetNextChunk(void *_cookie, const void **chunkBuffer,
514 size_t *chunkSize, media_header *mediaHeader)
516 asf_cookie *cookie = (asf_cookie *)_cookie;
517 uint32 size;
518 bool keyframe;
520 if (theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &(cookie->buffer), &size, &keyframe, &mediaHeader->start_time) == false) {
521 TRACE("LAST BUFFER : Stream %d (%ld)\n",cookie->stream, cookie->frame_pos);
522 *chunkSize = 0;
523 *chunkBuffer = NULL;
524 return B_LAST_BUFFER_ERROR;
527 if (cookie->audio) {
528 TRACE("Audio");
529 mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
530 mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
531 } else {
532 TRACE("Video");
533 mediaHeader->type = B_MEDIA_ENCODED_VIDEO;
534 mediaHeader->u.encoded_video.field_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
535 mediaHeader->u.encoded_video.first_active_line = 0;
536 mediaHeader->u.encoded_video.line_count = cookie->line_count;
537 mediaHeader->u.encoded_video.field_number = 0;
538 mediaHeader->u.encoded_video.field_sequence = cookie->frame_pos;
541 TRACE(" stream %d: frame %ld start time %.6f Size %ld key frame %s\n",cookie->stream, cookie->frame_pos, mediaHeader->start_time / 1000000.0, size, keyframe ? "true" : "false");
543 cookie->frame_pos++;
545 *chunkBuffer = cookie->buffer;
546 *chunkSize = size;
548 return B_OK;
552 Reader *
553 asfReaderPlugin::NewReader()
555 return new asfReader;
559 MediaPlugin *instantiate_plugin()
561 return new asfReaderPlugin;