status_t OpenSoundDevice::register_media_formats() { status_t err; int i, count; BMediaFormats formats; if (formats.InitCheck() < B_OK) return formats.InitCheck(); media_format format; for (i = 0; gSupportedFormats[i]; i++) { media_format_description desc[10]; err = count = get_media_format_description_for(gSupportedFormats[i], desc, 10); if (err < 1) continue; if (gSupportedFormats[i] & AFMT_SUPPORTED_PCM) { format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio = media_multi_audio_format::wildcard; } else { format.type = B_MEDIA_ENCODED_AUDIO; format.u.encoded_audio = media_encoded_audio_format::wildcard; } err = formats.MakeFormatFor(desc, count, &format); PRINT(("OpenSoundDevice::register_media_formats: MakeFormatFor: %s\n", strerror(err))); } return B_OK; };
status_t MusePackPlugin::GetSupportedFormats(media_format ** formats, size_t * count) { media_format_description description; description.family = B_MISC_FORMAT_FAMILY; description.u.misc.file_format = 'mpc '; description.u.misc.codec = 'MPC7'; // 7 is the most recent stream version media_format format; format.type = B_MEDIA_ENCODED_AUDIO; format.u.encoded_audio = media_encoded_audio_format::wildcard; BMediaFormats mediaFormats; status_t result = mediaFormats.InitCheck(); if (result != B_OK) { return result; } result = mediaFormats.MakeFormatFor(&description, 1, &format); if (result != B_OK) { return result; } muse_pack_formats[0] = format; *formats = muse_pack_formats; *count = 1; return B_OK; }
status_t mp3DecoderPlugin::GetSupportedFormats(media_format ** formats, size_t * count) { const mpeg_id ids[] = { B_MPEG_1_AUDIO_LAYER_1, B_MPEG_1_AUDIO_LAYER_2, B_MPEG_1_AUDIO_LAYER_3, // "MP3" B_MPEG_2_AUDIO_LAYER_1, B_MPEG_2_AUDIO_LAYER_2, B_MPEG_2_AUDIO_LAYER_3, B_MPEG_2_5_AUDIO_LAYER_1, B_MPEG_2_5_AUDIO_LAYER_2, B_MPEG_2_5_AUDIO_LAYER_3, }; const size_t otherIDs = 6; const size_t numIDs = otherIDs + sizeof(ids) / sizeof(mpeg_id); media_format_description descriptions[numIDs]; descriptions[0].family = B_WAV_FORMAT_FAMILY; descriptions[0].u.wav.codec = 0x0050; descriptions[1].family = B_WAV_FORMAT_FAMILY; descriptions[1].u.wav.codec = 0x0055; descriptions[2].family = B_QUICKTIME_FORMAT_FAMILY; descriptions[2].u.quicktime.codec = '.mp3'; descriptions[3].family = B_QUICKTIME_FORMAT_FAMILY; descriptions[3].u.quicktime.codec = '3pm.'; descriptions[4].family = B_AVI_FORMAT_FAMILY; descriptions[4].u.avi.codec = '.mp3'; descriptions[5].family = B_AVI_FORMAT_FAMILY; descriptions[5].u.avi.codec = '3pm.'; for (size_t i = otherIDs; i < numIDs; i++) { descriptions[i].family = B_MPEG_FORMAT_FAMILY; descriptions[i].u.mpeg.id = ids[i-otherIDs]; } media_format format; format.type = B_MEDIA_ENCODED_AUDIO; format.u.encoded_audio = media_encoded_audio_format::wildcard; format.u.encoded_audio.output.format = media_raw_audio_format::B_AUDIO_SHORT; format.u.encoded_audio.output.byte_order = B_MEDIA_HOST_ENDIAN; BMediaFormats mediaFormats; status_t result = mediaFormats.InitCheck(); if (result != B_OK) { return result; } result = mediaFormats.MakeFormatFor(descriptions, numIDs, &format); if (result != B_OK) { return result; } mp3_formats[0] = format; *formats = mp3_formats; *count = 1; return result; }
status_t build_decoder_formats(media_format** _formats, size_t* _count) { BMediaFormats mediaFormats; if (mediaFormats.InitCheck() != B_OK) return B_ERROR; int32 index = 0; AVCodec* codec = NULL; while ((codec = av_codec_next(codec)) != NULL) { if (index >= sMaxFormatCount) { fprintf(stderr, "Maximum format count reached for auto-generated " "AVCodec to media_format mapping, but there are still more " "AVCodecs compiled into libavcodec!\n"); break; } media_format format; // Determine media type switch (codec->type) { case AVMEDIA_TYPE_VIDEO: format.type = B_MEDIA_ENCODED_VIDEO; break; case AVMEDIA_TYPE_AUDIO: format.type = B_MEDIA_ENCODED_AUDIO; break; default: // ignore this AVCodec continue; } media_format_description description; memset(&description, 0, sizeof(description)); // Hard-code everything to B_MISC_FORMAT_FAMILY to ease matching // later on. description.family = B_MISC_FORMAT_FAMILY; description.u.misc.file_format = 'ffmp'; description.u.misc.codec = codec->id; format.require_flags = 0; format.deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; if (mediaFormats.MakeFormatFor(&description, 1, &format) != B_OK) return B_ERROR; gAVCodecFormats[index] = format; index++; } *_formats = gAVCodecFormats; *_count = index; return B_OK; }
status_t OpenSoundDevice::get_media_format_for(int fmt, media_format &format) { status_t err; BMediaFormats formats; if (formats.InitCheck() < B_OK) return formats.InitCheck(); /* shortcut for raw */ if (fmt & AFMT_SUPPORTED_PCM) { format = media_format(); format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio = media_raw_audio_format::wildcard; return B_OK; } media_format_description desc; err = get_media_format_description_for(fmt, &desc); if (err < B_OK) return err; err = formats.GetFormatFor(desc, &format); return err; };
static status_t get_text_format(tobias_stream_header * header, media_format * format) { TRACE(" get_text_format\n"); // get the format for the description media_format_description description = tobias_text_description(); BMediaFormats formats; status_t result = formats.InitCheck(); if (result == B_OK) { result = formats.GetFormatFor(description, format); } if (result != B_OK) { *format = tobias_text_encoded_media_format(); // ignore error, allow user to use ReadChunk interface } // fill out format from header packet return B_OK; }
static status_t get_video_format(tobias_stream_header * header, media_format * format) { TRACE(" get_video_format\n"); // get the format for the description media_format_description description = tobias_video_description(); description.u.avi.codec = header->subtype[3] << 24 | header->subtype[2] << 16 | header->subtype[1] << 8 | header->subtype[0]; BMediaFormats formats; status_t result = formats.InitCheck(); if (result == B_OK) { result = formats.GetFormatFor(description, format); } if (result != B_OK) { *format = tobias_video_encoded_media_format(); // ignore error, allow user to use ReadChunk interface } // fill out format from header packet format->user_data_type = B_CODEC_TYPE_INFO; strncpy((char*)format->user_data, header->subtype, 4); format->u.encoded_video.frame_size = header->video.width * header->video.height; format->u.encoded_video.output.field_rate = 10000000.0 / header->time_unit; format->u.encoded_video.output.interlace = 1; format->u.encoded_video.output.first_active = 0; format->u.encoded_video.output.last_active = header->video.height - 1; format->u.encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT; format->u.encoded_video.output.pixel_width_aspect = 1; format->u.encoded_video.output.pixel_height_aspect = 1; format->u.encoded_video.output.display.line_width = header->video.width; format->u.encoded_video.output.display.line_count = header->video.height; format->u.encoded_video.output.display.bytes_per_row = 0; format->u.encoded_video.output.display.pixel_offset = 0; format->u.encoded_video.output.display.line_offset = 0; format->u.encoded_video.output.display.flags = 0; // TODO: wring more info out of the headers return B_OK; }
static status_t get_audio_format(tobias_stream_header * header, media_format * format) { TRACE(" get_audio_format\n"); // get the format for the description media_format_description description = tobias_audio_description(); unsigned int wav_id = 0; sscanf(header->subtype, "%04x", &wav_id); description.u.wav.codec = wav_id; BMediaFormats formats; status_t result = formats.InitCheck(); if (result == B_OK) { result = formats.GetFormatFor(description, format); } if (result != B_OK) { *format = tobias_audio_encoded_media_format(); // ignore error, allow user to use ReadChunk interface } // fill out format from header packet format->user_data_type = B_CODEC_TYPE_INFO; strncpy((char*)format->user_data, header->subtype, 4); format->u.encoded_audio.bit_rate = header->audio.avgbytespersec * 8; if (header->audio.channels == 1) { format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT; } else { format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT; } format->u.encoded_audio.output.frame_rate = header->samples_per_unit * 10000000.0 / header->time_unit; format->u.encoded_audio.output.channel_count = header->audio.channels; format->u.encoded_audio.output.buffer_size = AudioBufferSize(&format->u.encoded_audio.output); // TODO: wring more info out of the headers return B_OK; }
status_t register_avcodec_tags(media_format_family family, const char *avname, int &index) { AVInputFormat *inputFormat = av_find_input_format(avname); if (inputFormat == NULL) return B_MEDIA_NO_HANDLER; BMediaFormats mediaFormats; if (mediaFormats.InitCheck() != B_OK) return B_ERROR; for (int tagSet = 0; inputFormat->codec_tag[tagSet]; tagSet++) { const AVCodecTag *tags = inputFormat->codec_tag[tagSet]; if (tags == NULL) continue; for (; tags->id != CODEC_ID_NONE; tags++) { // XXX: we might want to keep some strange PCM codecs too... // skip unwanted codec tags if (tags->tag == CODEC_ID_RAWVIDEO || (tags->tag >= CODEC_ID_PCM_S16LE && tags->tag < CODEC_ID_ADPCM_IMA_QT) || tags->tag >= CODEC_ID_DVD_SUBTITLE) continue; if (index >= sMaxFormatCount) { fprintf(stderr, "Maximum format count reached for auto-generated " "AVCodec to media_format mapping, but there are still more " "AVCodecs compiled into libavcodec!\n"); break; } media_format format; // Determine media type if (tags->tag < CODEC_ID_PCM_S16LE) format.type = B_MEDIA_ENCODED_VIDEO; else format.type = B_MEDIA_ENCODED_AUDIO; media_format_description description; memset(&description, 0, sizeof(description)); // Hard-code everything to B_MISC_FORMAT_FAMILY to ease matching // later on. description.family = family; switch (family) { case B_AIFF_FORMAT_FAMILY: description.u.aiff.codec = tags->tag; break; case B_AVI_FORMAT_FAMILY: description.u.avi.codec = tags->tag; break; case B_MPEG_FORMAT_FAMILY: description.u.mpeg.id = tags->tag; break; case B_QUICKTIME_FORMAT_FAMILY: description.u.quicktime.codec = tags->tag; break; case B_WAV_FORMAT_FAMILY: description.u.wav.codec = tags->tag; break; default: break; } format.require_flags = 0; format.deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; if (mediaFormats.MakeFormatFor(&description, 1, &format) != B_OK) return B_ERROR; gAVCodecFormats[index] = format; index++; } } return B_OK; }
status_t OggVorbisSeekable::GetStreamInfo(int64 *frameCount, bigtime_t *duration, media_format *format) { TRACE("OggVorbisSeekable::GetStreamInfo\n"); status_t result = B_OK; ogg_packet packet; // get header packet if (GetHeaderPackets().size() < 1) { result = GetPacket(&packet); if (result != B_OK) { return result; } SaveHeaderPacket(packet); } packet = GetHeaderPackets()[0]; if (!packet.b_o_s) { return B_ERROR; // first packet was not beginning of stream } // parse header packet // based on libvorbis/info.c vorbis_synthesis_headerin(...) oggpack_buffer opb; oggpack_readinit(&opb, packet.packet, packet.bytes); int packtype = oggpack_read(&opb, 8); if (packtype != 0x01) { return B_ERROR; // first packet was not an info packet } // discard vorbis string for (uint i = 0 ; i < sizeof("vorbis") - 1 ; i++) { oggpack_read(&opb, 8); } vorbis_info info; if (_vorbis_unpack_info(&info, &opb) != 0) { return B_ERROR; // couldn't unpack info } // get the format for the description media_format_description description = vorbis_description(); BMediaFormats formats; result = formats.InitCheck(); if (result == B_OK) { result = formats.GetFormatFor(description, format); } if (result != B_OK) { *format = vorbis_encoded_media_format(); // ignore error, allow user to use ReadChunk interface } // fill out format from header packet if (info.bitrate_nominal > 0) { format->u.encoded_audio.bit_rate = info.bitrate_nominal; } else if (info.bitrate_upper > 0) { format->u.encoded_audio.bit_rate = info.bitrate_upper; } else if (info.bitrate_lower > 0) { format->u.encoded_audio.bit_rate = info.bitrate_lower; } if (info.channels == 1) { format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT; } else { format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT; } fFrameRate = format->u.encoded_audio.output.frame_rate = (float)info.rate; format->u.encoded_audio.output.channel_count = info.channels; format->u.encoded_audio.output.buffer_size = AudioBufferSize(&format->u.encoded_audio.output); // get comment packet if (GetHeaderPackets().size() < 2) { result = GetPacket(&packet); if (result != B_OK) { return result; } SaveHeaderPacket(packet); } // get codebook packet if (GetHeaderPackets().size() < 3) { result = GetPacket(&packet); if (result != B_OK) { return result; } SaveHeaderPacket(packet); } format->SetMetaData((void*)&GetHeaderPackets(),sizeof(GetHeaderPackets())); // TODO: count the frames in the first page.. somehow.. :-/ int64 frames = 0; ogg_page page; // read the first page result = ReadPage(&page); if (result != B_OK) { return result; } int64 fFirstGranulepos = ogg_page_granulepos(&page); TRACE("OggVorbisSeekable::GetStreamInfo: first granulepos: %lld\n", fFirstGranulepos); // read our last page off_t last = inherited::Seek(GetLastPagePosition(), SEEK_SET); if (last < 0) { return last; } result = ReadPage(&page); if (result != B_OK) { return result; } int64 last_granulepos = ogg_page_granulepos(&page); // seek back to the start int64 frame = 0; bigtime_t time = 0; result = Seek(B_MEDIA_SEEK_TO_TIME, &frame, &time); if (result != B_OK) { return result; } // compute frame count and duration from sample count frames = last_granulepos - fFirstGranulepos; *frameCount = frames; *duration = (1000000LL * frames) / (long long)fFrameRate; return B_OK; }