/*! \brief Updates relevant fields of the class member fHeader with the properties of the most recently decoded video frame. It is assumed that this function is called only when the following asserts hold true: 1. We actually got a new picture decoded by the video decoder. 2. fHeader wasn't updated for the new picture yet. You MUST call this method only once per decoded video frame. 3. This function MUST be called before _DeinterlaceAndColorConvertVideoFrame() as the later one relys on an updated fHeader. 4. There will be at maximumn only one decoded video frame in our cache at any single point in time. Otherwise you couldn't tell to which cached decoded video frame the properties in fHeader relate to. 5. AVCodecContext is still valid for this video frame (This is the case when this function is called immediately after avcodec_decode_video2(). */ void AVCodecDecoder::_UpdateMediaHeaderForVideoFrame() { fHeader.type = B_MEDIA_RAW_VIDEO; fHeader.file_pos = 0; fHeader.orig_size = 0; fHeader.start_time = fRawDecodedPicture->reordered_opaque; fHeader.u.raw_video.display_line_width = fRawDecodedPicture->width; fHeader.u.raw_video.display_line_count = fRawDecodedPicture->height; fHeader.u.raw_video.bytes_per_row = CalculateBytesPerRowWithColorSpaceAndVideoWidth(fOutputColorSpace, fRawDecodedPicture->width); fHeader.u.raw_video.field_gamma = 1.0; fHeader.u.raw_video.field_sequence = fFrame; fHeader.u.raw_video.field_number = 0; fHeader.u.raw_video.pulldown_number = 0; fHeader.u.raw_video.first_active_line = 1; fHeader.u.raw_video.line_count = fRawDecodedPicture->height; ConvertAVCodecContextToVideoAspectWidthAndHeight(*fContext, fHeader.u.raw_video.pixel_width_aspect, fHeader.u.raw_video.pixel_height_aspect); TRACE("[v] start_time=%02d:%02d.%02d field_sequence=%lu\n", int((fHeader.start_time / 60000000) % 60), int((fHeader.start_time / 1000000) % 60), int((fHeader.start_time / 10000) % 100), fHeader.u.raw_video.field_sequence); }
status_t AVFormatReader::Stream::Init(int32 virtualIndex) { TRACE("AVFormatReader::Stream::Init(%ld)\n", virtualIndex); status_t ret = StreamBase::Init(virtualIndex); if (ret != B_OK) return ret; // Get a pointer to the AVCodecContext for the stream at streamIndex. AVCodecContext* codecContext = fStream->codec; #if 0 // stippi: Here I was experimenting with the question if some fields of the // AVCodecContext change (or get filled out at all), if the AVCodec is opened. class CodecOpener { public: CodecOpener(AVCodecContext* context) { fCodecContext = context; AVCodec* codec = avcodec_find_decoder(context->codec_id); fCodecOpen = avcodec_open(context, codec) >= 0; if (!fCodecOpen) TRACE(" failed to open the codec!\n"); } ~CodecOpener() { if (fCodecOpen) avcodec_close(fCodecContext); } private: AVCodecContext* fCodecContext; bool fCodecOpen; } codecOpener(codecContext); #endif // initialize the media_format for this stream media_format* format = &fFormat; memset(format, 0, sizeof(media_format)); media_format_description description; // Set format family and type depending on codec_type of the stream. switch (codecContext->codec_type) { case AVMEDIA_TYPE_AUDIO: if ((codecContext->codec_id >= CODEC_ID_PCM_S16LE) && (codecContext->codec_id <= CODEC_ID_PCM_U8)) { TRACE(" raw audio\n"); format->type = B_MEDIA_RAW_AUDIO; description.family = B_ANY_FORMAT_FAMILY; // This will then apparently be handled by the (built into // BMediaTrack) RawDecoder. } else { TRACE(" encoded audio\n"); format->type = B_MEDIA_ENCODED_AUDIO; description.family = B_MISC_FORMAT_FAMILY; description.u.misc.file_format = 'ffmp'; } break; case AVMEDIA_TYPE_VIDEO: TRACE(" encoded video\n"); format->type = B_MEDIA_ENCODED_VIDEO; description.family = B_MISC_FORMAT_FAMILY; description.u.misc.file_format = 'ffmp'; break; default: TRACE(" unknown type\n"); format->type = B_MEDIA_UNKNOWN_TYPE; return B_ERROR; break; } if (format->type == B_MEDIA_RAW_AUDIO) { // We cannot describe all raw-audio formats, some are unsupported. switch (codecContext->codec_id) { case CODEC_ID_PCM_S16LE: format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; format->u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN; break; case CODEC_ID_PCM_S16BE: format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; format->u.raw_audio.byte_order = B_MEDIA_BIG_ENDIAN; break; case CODEC_ID_PCM_U16LE: // format->u.raw_audio.format // = media_raw_audio_format::B_AUDIO_USHORT; // format->u.raw_audio.byte_order // = B_MEDIA_LITTLE_ENDIAN; return B_NOT_SUPPORTED; break; case CODEC_ID_PCM_U16BE: // format->u.raw_audio.format // = media_raw_audio_format::B_AUDIO_USHORT; // format->u.raw_audio.byte_order // = B_MEDIA_BIG_ENDIAN; return B_NOT_SUPPORTED; break; case CODEC_ID_PCM_S8: format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_CHAR; break; case CODEC_ID_PCM_U8: format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_UCHAR; break; default: return B_NOT_SUPPORTED; break; } } else { if (description.family == B_MISC_FORMAT_FAMILY) description.u.misc.codec = codecContext->codec_id; BMediaFormats formats; status_t status = formats.GetFormatFor(description, format); if (status < B_OK) TRACE(" formats.GetFormatFor() error: %s\n", strerror(status)); format->user_data_type = B_CODEC_TYPE_INFO; *(uint32*)format->user_data = codecContext->codec_tag; format->user_data[4] = 0; } format->require_flags = 0; format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; switch (format->type) { case B_MEDIA_RAW_AUDIO: format->u.raw_audio.frame_rate = (float)codecContext->sample_rate; format->u.raw_audio.channel_count = codecContext->channels; format->u.raw_audio.channel_mask = codecContext->channel_layout; format->u.raw_audio.byte_order = avformat_to_beos_byte_order(codecContext->sample_fmt); ConvertAVSampleFormatToRawAudioFormat(codecContext->sample_fmt, format->u.raw_audio.format); format->u.raw_audio.buffer_size = 0; // Read one packet and mark it for later re-use. (So our first // GetNextChunk() call does not read another packet.) if (_NextPacket(true) == B_OK) { TRACE(" successfully determined audio buffer size: %d\n", fPacket.size); format->u.raw_audio.buffer_size = fPacket.size; } break; case B_MEDIA_ENCODED_AUDIO: format->u.encoded_audio.bit_rate = codecContext->bit_rate; format->u.encoded_audio.frame_size = codecContext->frame_size; // Fill in some info about possible output format format->u.encoded_audio.output = media_multi_audio_format::wildcard; format->u.encoded_audio.output.frame_rate = (float)codecContext->sample_rate; // Channel layout bits match in Be API and FFmpeg. format->u.encoded_audio.output.channel_count = codecContext->channels; format->u.encoded_audio.multi_info.channel_mask = codecContext->channel_layout; format->u.encoded_audio.output.byte_order = avformat_to_beos_byte_order(codecContext->sample_fmt); ConvertAVSampleFormatToRawAudioFormat(codecContext->sample_fmt, format->u.encoded_audio.output.format); if (codecContext->block_align > 0) { format->u.encoded_audio.output.buffer_size = codecContext->block_align; } else { format->u.encoded_audio.output.buffer_size = codecContext->frame_size * codecContext->channels * (format->u.encoded_audio.output.format & media_raw_audio_format::B_AUDIO_SIZE_MASK); } break; case B_MEDIA_ENCODED_VIDEO: // TODO: Specifying any of these seems to throw off the format matching // later on. // format->u.encoded_video.avg_bit_rate = codecContext->bit_rate; // format->u.encoded_video.max_bit_rate = codecContext->bit_rate // + codecContext->bit_rate_tolerance; // format->u.encoded_video.encoding // = media_encoded_video_format::B_ANY; // format->u.encoded_video.frame_size = 1; // format->u.encoded_video.forward_history = 0; // format->u.encoded_video.backward_history = 0; format->u.encoded_video.output.field_rate = FrameRate(); format->u.encoded_video.output.interlace = 1; format->u.encoded_video.output.first_active = 0; format->u.encoded_video.output.last_active = codecContext->height - 1; // TODO: Maybe libavformat actually provides that info // somewhere... format->u.encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT; ConvertAVCodecContextToVideoAspectWidthAndHeight(*codecContext, format->u.encoded_video.output.pixel_width_aspect, format->u.encoded_video.output.pixel_height_aspect); format->u.encoded_video.output.display.format = pixfmt_to_colorspace(codecContext->pix_fmt); format->u.encoded_video.output.display.line_width = codecContext->width; format->u.encoded_video.output.display.line_count = codecContext->height; TRACE(" width/height: %d/%d\n", codecContext->width, codecContext->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 break; default: // This is an unknown format to us. break; } // Add the meta data, if any if (codecContext->extradata_size > 0) { format->SetMetaData(codecContext->extradata, codecContext->extradata_size); TRACE(" extradata: %p\n", format->MetaData()); } TRACE(" extradata_size: %d\n", codecContext->extradata_size); // TRACE(" intra_matrix: %p\n", codecContext->intra_matrix); // TRACE(" inter_matrix: %p\n", codecContext->inter_matrix); // TRACE(" get_buffer(): %p\n", codecContext->get_buffer); // TRACE(" release_buffer(): %p\n", codecContext->release_buffer); #ifdef TRACE_AVFORMAT_READER char formatString[512]; if (string_for_format(*format, formatString, sizeof(formatString))) TRACE(" format: %s\n", formatString); uint32 encoding = format->Encoding(); TRACE(" encoding '%.4s'\n", (char*)&encoding); #endif return B_OK; }