| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/media/playback/mediaplayer/ffmpeg/av_codec_context.h" |
| |
| #include <endian.h> |
| |
| #include "src/lib/syslog/cpp/logger.h" |
| #include "src/media/playback/mediaplayer/ffmpeg/ffmpeg_init.h" |
| #include "src/media/playback/mediaplayer/graph/types/audio_stream_type.h" |
| #include "src/media/playback/mediaplayer/graph/types/subpicture_stream_type.h" |
| #include "src/media/playback/mediaplayer/graph/types/text_stream_type.h" |
| #include "src/media/playback/mediaplayer/graph/types/video_stream_type.h" |
| extern "C" { |
| #include "libavformat/avformat.h" |
| #include "libavutil/encryption_info.h" |
| } |
| |
| namespace media_player { |
| |
| namespace { |
| |
| constexpr uint32_t kPsshType = 0x70737368; // fourcc 'pssh' |
| constexpr uint32_t kSystemIdSize = 16; // System IDs in pssh boxes are always 16 bytes. |
| constexpr uint32_t kKeyIdSize = 16; // Key IDs in pssh boxes are always 16 bytes. |
| |
| // Deposits |size| bytes copied from |data| at |*p_in_out| and increases |*p_in_out| by |size|. |
| void Deposit(const uint8_t* data, size_t size, uint8_t** p_in_out) { |
| FX_DCHECK(size); |
| FX_DCHECK(data); |
| FX_DCHECK(p_in_out); |
| FX_DCHECK(*p_in_out); |
| memcpy(*p_in_out, data, size); |
| *p_in_out += size; |
| } |
| |
| // Deposits |t| at |*p_in_out| and increases |*p_in_out| by |sizeof(t)|. |
| template <typename T> |
| void Deposit(T t, uint8_t** p_in_out) { |
| Deposit(reinterpret_cast<const uint8_t*>(&t), sizeof(t), p_in_out); |
| } |
| |
| // Creates a PSSH box as raw bytes from encryption init data on a stream, if there is any, otherwise |
| // returns nullptr. |
| std::unique_ptr<Bytes> EncryptionParametersFromStream(const AVStream& from) { |
| int encryption_side_data_size; |
| uint8_t* encryption_side_data = |
| av_stream_get_side_data(&from, AV_PKT_DATA_ENCRYPTION_INIT_INFO, &encryption_side_data_size); |
| if (encryption_side_data == nullptr) { |
| return nullptr; |
| } |
| |
| // Create an |AVEncryptionInitInfo| structure from the side data. This is deleted below by |
| // calling |av_encryption_init_info_free|. |
| AVEncryptionInitInfo* encryption_init_info = |
| av_encryption_init_info_get_side_data(encryption_side_data, encryption_side_data_size); |
| |
| // A pssh box has the following structure. Numeric values are big-endian. |
| // |
| // uint32_t size; |
| // uint32_t type; // fourcc 'pssh' |
| // uint8_t version; |
| // uint8_t flags[3]; // all zeros |
| // uint8_t system_id[16]; |
| // if (version_ > 0) { |
| // uint32_t key_id_count; |
| // uint8_t key_ids[16][kid_count]; |
| // } |
| // uint32_t data_size; |
| // uint8_t data[data_size]; |
| |
| struct __attribute__((packed)) PsshBoxInvariantPrefix { |
| uint32_t size_; |
| uint32_t type_; |
| uint8_t version_; |
| uint8_t flags_[3]; |
| uint8_t system_id_[kSystemIdSize]; |
| }; |
| |
| // Determine the size of the pssh box. |
| uint32_t box_size = |
| sizeof(PsshBoxInvariantPrefix) + sizeof(uint32_t) + encryption_init_info->data_size; |
| if (encryption_init_info->num_key_ids != 0) { |
| box_size += sizeof(uint32_t) + kKeyIdSize * encryption_init_info->num_key_ids; |
| FX_DCHECK(encryption_init_info->key_id_size == kKeyIdSize); |
| } |
| |
| // Create a buffer of the correct size. |
| auto result = Bytes::Create(box_size); |
| |
| // Align |prefix| with the start of the buffer and populate it. |
| auto prefix = new (result->data()) PsshBoxInvariantPrefix; |
| prefix->size_ = htobe32(box_size); |
| prefix->type_ = htobe32(kPsshType); |
| prefix->version_ = (encryption_init_info->num_key_ids == 0) ? 0 : 1; |
| prefix->flags_[0] = 0; |
| prefix->flags_[1] = 0; |
| prefix->flags_[2] = 0; |
| |
| FX_DCHECK(encryption_init_info->system_id_size == kSystemIdSize); |
| memcpy(prefix->system_id_, encryption_init_info->system_id, kSystemIdSize); |
| |
| // Set |p| to point to the first byte after |prefix|. |p| will be our write pointer into |
| // |result->data()| as we write the key IDs, data size and data. |
| auto p = reinterpret_cast<uint8_t*>(prefix + 1); |
| |
| // Deposit the key IDs. |
| if (encryption_init_info->num_key_ids != 0) { |
| Deposit(htobe32(encryption_init_info->num_key_ids), &p); |
| for (uint32_t i = 0; i < encryption_init_info->num_key_ids; ++i) { |
| FX_DCHECK(encryption_init_info->key_ids[i]); |
| Deposit(encryption_init_info->key_ids[i], kKeyIdSize, &p); |
| } |
| } |
| |
| // Deposit the data size and data. |
| Deposit(htobe32(encryption_init_info->data_size), &p); |
| Deposit(encryption_init_info->data, encryption_init_info->data_size, &p); |
| |
| FX_DCHECK(p == result->data() + box_size); |
| |
| av_encryption_init_info_free(encryption_init_info); |
| |
| return result; |
| } |
| |
| // Converts an AVSampleFormat into an AudioStreamType::SampleFormat. |
| AudioStreamType::SampleFormat Convert(AVSampleFormat av_sample_format) { |
| switch (av_sample_format) { |
| case AV_SAMPLE_FMT_NONE: |
| return AudioStreamType::SampleFormat::kNone; |
| case AV_SAMPLE_FMT_U8: |
| case AV_SAMPLE_FMT_U8P: |
| return AudioStreamType::SampleFormat::kUnsigned8; |
| case AV_SAMPLE_FMT_S16: |
| case AV_SAMPLE_FMT_S16P: |
| return AudioStreamType::SampleFormat::kSigned16; |
| case AV_SAMPLE_FMT_S32: |
| case AV_SAMPLE_FMT_S32P: |
| return AudioStreamType::SampleFormat::kSigned24In32; |
| case AV_SAMPLE_FMT_FLT: |
| case AV_SAMPLE_FMT_FLTP: |
| return AudioStreamType::SampleFormat::kFloat; |
| case AV_SAMPLE_FMT_DBL: |
| case AV_SAMPLE_FMT_DBLP: |
| case AV_SAMPLE_FMT_NB: |
| default: |
| FX_LOGS(ERROR) << "unsupported av_sample_format " << av_sample_format; |
| abort(); |
| } |
| } |
| |
| template <typename T> |
| std::unique_ptr<Bytes> BytesFromExtraData(T& from) { |
| return from.extradata_size == 0 ? nullptr : Bytes::Create(from.extradata, from.extradata_size); |
| } |
| |
| // Copies a buffer from Bytes into context->extradata. The result is malloc'ed |
| // and must be freed. |
| void ExtraDataFromBytes(const Bytes& bytes, const AvCodecContextPtr& context) { |
| size_t byte_count = bytes.size(); |
| uint8_t* copy = reinterpret_cast<uint8_t*>(malloc(byte_count)); |
| std::memcpy(copy, bytes.data(), byte_count); |
| context->extradata = copy; |
| context->extradata_size = byte_count; |
| } |
| |
| // Gets the encoding from a codec_id. |
| const char* EncodingFromCodecId(AVCodecID from) { |
| switch (from) { |
| case AV_CODEC_ID_AAC: |
| return StreamType::kAudioEncodingAac; |
| case AV_CODEC_ID_AAC_LATM: |
| return StreamType::kAudioEncodingAacLatm; |
| case AV_CODEC_ID_AMR_NB: |
| return StreamType::kAudioEncodingAmrNb; |
| case AV_CODEC_ID_AMR_WB: |
| return StreamType::kAudioEncodingAmrWb; |
| case AV_CODEC_ID_APTX: |
| return StreamType::kAudioEncodingAptX; |
| case AV_CODEC_ID_FLAC: |
| return StreamType::kAudioEncodingFlac; |
| case AV_CODEC_ID_GSM_MS: |
| return StreamType::kAudioEncodingGsmMs; |
| case AV_CODEC_ID_MP3: |
| return StreamType::kAudioEncodingMp3; |
| case AV_CODEC_ID_OPUS: |
| return StreamType::kAudioEncodingOpus; |
| case AV_CODEC_ID_PCM_ALAW: |
| return StreamType::kAudioEncodingPcmALaw; |
| case AV_CODEC_ID_PCM_MULAW: |
| return StreamType::kAudioEncodingPcmMuLaw; |
| case AV_CODEC_ID_SBC: |
| return StreamType::kAudioEncodingSbc; |
| case AV_CODEC_ID_VORBIS: |
| return StreamType::kAudioEncodingVorbis; |
| case AV_CODEC_ID_H263: |
| return StreamType::kVideoEncodingH263; |
| case AV_CODEC_ID_H264: |
| return StreamType::kVideoEncodingH264; |
| case AV_CODEC_ID_MPEG4: |
| return StreamType::kVideoEncodingMpeg4; |
| case AV_CODEC_ID_THEORA: |
| return StreamType::kVideoEncodingTheora; |
| case AV_CODEC_ID_VP3: |
| return StreamType::kVideoEncodingVp3; |
| case AV_CODEC_ID_VP8: |
| return StreamType::kVideoEncodingVp8; |
| case AV_CODEC_ID_VP9: |
| return StreamType::kVideoEncodingVp9; |
| default: |
| FX_LOGS(WARNING) << "unsupported codec_id " << avcodec_get_name(from); |
| return StreamType::kMediaEncodingUnsupported; |
| } |
| } |
| |
| // Determines if codec_id represents an LPCM audio format. |
| bool IsLpcm(AVCodecID codec_id) { |
| switch (codec_id) { |
| case AV_CODEC_ID_PCM_F32LE: |
| case AV_CODEC_ID_PCM_S16BE: |
| case AV_CODEC_ID_PCM_S16LE: |
| case AV_CODEC_ID_PCM_S24BE: |
| case AV_CODEC_ID_PCM_S24LE: |
| case AV_CODEC_ID_PCM_U8: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| // Creates a StreamType from an AVCodecContext describing an audio type. |
| std::unique_ptr<StreamType> StreamTypeFromAudioCodecContext(const AVCodecContext& from) { |
| bool decoded = from.codec != nullptr || IsLpcm(from.codec_id); |
| |
| return AudioStreamType::Create( |
| nullptr, decoded ? StreamType::kAudioEncodingLpcm : EncodingFromCodecId(from.codec_id), |
| decoded ? nullptr : BytesFromExtraData(from), Convert(from.sample_fmt), from.channels, |
| from.sample_rate); |
| } |
| |
| // Creates a StreamType from an AVCodecContext describing an audio type. |
| std::unique_ptr<StreamType> StreamTypeFromAudioStream(const AVStream& from) { |
| FX_DCHECK(from.codecpar); |
| |
| auto& codecpar = *from.codecpar; |
| bool decoded = IsLpcm(codecpar.codec_id); |
| |
| return AudioStreamType::Create( |
| EncryptionParametersFromStream(from), |
| decoded ? StreamType::kAudioEncodingLpcm : EncodingFromCodecId(codecpar.codec_id), |
| decoded ? nullptr : BytesFromExtraData(codecpar), |
| Convert(static_cast<AVSampleFormat>(codecpar.format)), codecpar.channels, |
| codecpar.sample_rate); |
| } |
| |
| // Converts AVColorSpace and AVColorRange to ColorSpace. |
| VideoStreamType::ColorSpace ColorSpaceFromAVColorSpaceAndRange(AVColorSpace color_space, |
| AVColorRange color_range) { |
| // TODO(dalesat): Blindly copied from Chromium. |
| if (color_range == AVCOL_RANGE_JPEG) { |
| return VideoStreamType::ColorSpace::kJpeg; |
| } |
| |
| switch (color_space) { |
| case AVCOL_SPC_UNSPECIFIED: |
| return VideoStreamType::ColorSpace::kNotApplicable; |
| case AVCOL_SPC_BT709: |
| return VideoStreamType::ColorSpace::kHdRec709; |
| case AVCOL_SPC_SMPTE170M: |
| case AVCOL_SPC_BT470BG: |
| return VideoStreamType::ColorSpace::kSdRec601; |
| default: |
| return VideoStreamType::ColorSpace::kUnknown; |
| } |
| } |
| |
| // Creates a StreamType from an AVCodecContext describing a video type. |
| std::unique_ptr<StreamType> StreamTypeFromVideoCodecContext(const AVCodecContext& from) { |
| int coded_width = from.coded_width; |
| int coded_height = from.coded_height; |
| avcodec_align_dimensions(const_cast<AVCodecContext*>(&from), &coded_width, &coded_height); |
| FX_DCHECK(coded_width >= from.coded_width); |
| FX_DCHECK(coded_height >= from.coded_height); |
| |
| uint32_t aspect_ratio_width = from.sample_aspect_ratio.num; |
| uint32_t aspect_ratio_height = from.sample_aspect_ratio.den; |
| if (aspect_ratio_width == 0 || aspect_ratio_height == 0) { |
| aspect_ratio_width = 1; |
| aspect_ratio_height = 1; |
| } |
| |
| uint32_t line_stride; |
| switch (from.pix_fmt) { |
| case AV_PIX_FMT_YUV420P: |
| case AV_PIX_FMT_YUVJ420P: |
| line_stride = coded_width; |
| break; |
| default: |
| line_stride = 0; |
| FX_LOGS(FATAL) << "Unrecognized pixel format " << from.pix_fmt; |
| } |
| |
| return VideoStreamType::Create( |
| nullptr, |
| from.codec == nullptr ? EncodingFromCodecId(from.codec_id) |
| : StreamType::kVideoEncodingUncompressed, |
| from.codec != nullptr ? nullptr : BytesFromExtraData(from), |
| PixelFormatFromAVPixelFormat(from.pix_fmt), |
| ColorSpaceFromAVColorSpaceAndRange(from.colorspace, from.color_range), from.width, |
| from.height, coded_width, coded_height, aspect_ratio_width, aspect_ratio_height, line_stride); |
| } |
| |
| // Creates a StreamType from an AVStream describing a video type. |
| std::unique_ptr<StreamType> StreamTypeFromVideoStream(const AVStream& from) { |
| const AVCodecParameters parameters = *from.codecpar; |
| |
| VideoStreamType::PixelFormat pixel_format = |
| PixelFormatFromAVPixelFormat(static_cast<AVPixelFormat>(parameters.format)); |
| |
| AVRational pixel_aspect_ratio = {1, 1}; |
| if (from.sample_aspect_ratio.num != 0 && from.sample_aspect_ratio.den != 0) { |
| pixel_aspect_ratio = from.sample_aspect_ratio; |
| } else if (parameters.sample_aspect_ratio.num != 0 && parameters.sample_aspect_ratio.den != 0) { |
| pixel_aspect_ratio = parameters.sample_aspect_ratio; |
| } |
| |
| return VideoStreamType::Create( |
| EncryptionParametersFromStream(from), EncodingFromCodecId(parameters.codec_id), |
| BytesFromExtraData(parameters), pixel_format, |
| ColorSpaceFromAVColorSpaceAndRange(parameters.color_space, parameters.color_range), |
| parameters.width, parameters.height, 0, 0, pixel_aspect_ratio.num, pixel_aspect_ratio.den, 0); |
| } |
| |
| // Creates a StreamType from an AVCodecContext describing a data type. |
| std::unique_ptr<StreamType> StreamTypeFromDataCodecContext(const AVCodecContext& from) { |
| // TODO(dalesat): Implement. |
| return TextStreamType::Create(nullptr, "UNSUPPORTED TYPE (FFMPEG DATA)", nullptr); |
| } |
| |
| // Creates a StreamType from AVCodecParameters describing a data type. |
| std::unique_ptr<StreamType> StreamTypeFromDataCodecParameters(const AVCodecParameters& from) { |
| // TODO(dalesat): Implement. |
| return TextStreamType::Create(nullptr, "UNSUPPORTED TYPE (FFMPEG DATA)", nullptr); |
| } |
| |
| // Creates a StreamType from an AVCodecContext describing a subtitle type. |
| std::unique_ptr<StreamType> StreamTypeFromSubtitleCodecContext(const AVCodecContext& from) { |
| // TODO(dalesat): Implement. |
| return SubpictureStreamType::Create(nullptr, "UNSUPPORTED TYPE (FFMPEG SUBTITLE)", nullptr); |
| } |
| |
| // Creates a StreamType from AVCodecParameters describing a subtitle type. |
| std::unique_ptr<StreamType> StreamTypeFromSubtitleCodecParameters(const AVCodecParameters& from) { |
| // TODO(dalesat): Implement. |
| return SubpictureStreamType::Create(nullptr, "UNSUPPORTED TYPE (FFMPEG SUBTITLE)", nullptr); |
| } |
| |
| // Creates an AVCodecContext from an AudioStreamType. |
| AvCodecContextPtr AVCodecContextFromAudioStreamType(const AudioStreamType& stream_type) { |
| FX_DCHECK(stream_type.medium() == StreamType::Medium::kAudio); |
| |
| AVCodecID codec_id; |
| AVSampleFormat sample_format = AV_SAMPLE_FMT_NONE; |
| |
| if (stream_type.encoding() == StreamType::kAudioEncodingLpcm) { |
| switch (stream_type.sample_format()) { |
| case AudioStreamType::SampleFormat::kUnsigned8: |
| codec_id = AV_CODEC_ID_PCM_U8; |
| sample_format = AV_SAMPLE_FMT_U8; |
| break; |
| case AudioStreamType::SampleFormat::kSigned16: |
| codec_id = AV_CODEC_ID_PCM_S16LE; |
| sample_format = AV_SAMPLE_FMT_S16; |
| break; |
| case AudioStreamType::SampleFormat::kSigned24In32: |
| codec_id = AV_CODEC_ID_PCM_S24LE; |
| sample_format = AV_SAMPLE_FMT_S32; |
| break; |
| case AudioStreamType::SampleFormat::kFloat: |
| codec_id = AV_CODEC_ID_PCM_F32LE; |
| sample_format = AV_SAMPLE_FMT_FLT; |
| break; |
| default: |
| FX_LOGS(ERROR) << "unsupported sample format"; |
| abort(); |
| } |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingAac) { |
| codec_id = AV_CODEC_ID_AAC; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingAacLatm) { |
| codec_id = AV_CODEC_ID_AAC_LATM; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingAmrNb) { |
| codec_id = AV_CODEC_ID_AMR_NB; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingAmrWb) { |
| codec_id = AV_CODEC_ID_AMR_WB; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingAptX) { |
| codec_id = AV_CODEC_ID_APTX; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingFlac) { |
| codec_id = AV_CODEC_ID_FLAC; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingGsmMs) { |
| codec_id = AV_CODEC_ID_GSM_MS; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingMp3) { |
| codec_id = AV_CODEC_ID_MP3; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingOpus) { |
| codec_id = AV_CODEC_ID_OPUS; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingPcmALaw) { |
| codec_id = AV_CODEC_ID_PCM_ALAW; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingPcmMuLaw) { |
| codec_id = AV_CODEC_ID_PCM_MULAW; |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingSbc) { |
| codec_id = AV_CODEC_ID_SBC; |
| switch (stream_type.sample_format()) { |
| case AudioStreamType::SampleFormat::kUnsigned8: |
| sample_format = AV_SAMPLE_FMT_U8P; |
| break; |
| case AudioStreamType::SampleFormat::kSigned16: |
| sample_format = AV_SAMPLE_FMT_S16P; |
| break; |
| case AudioStreamType::SampleFormat::kSigned24In32: |
| sample_format = AV_SAMPLE_FMT_S32P; |
| break; |
| case AudioStreamType::SampleFormat::kFloat: |
| sample_format = AV_SAMPLE_FMT_FLTP; |
| break; |
| default: |
| FX_LOGS(ERROR) << "unsupported sample format"; |
| abort(); |
| } |
| } else if (stream_type.encoding() == StreamType::kAudioEncodingVorbis) { |
| codec_id = AV_CODEC_ID_VORBIS; |
| } else if (stream_type.encoding() == StreamType::kMediaEncodingUnsupported) { |
| codec_id = AV_CODEC_ID_NONE; |
| } else { |
| FX_LOGS(WARNING) << "unsupported encoding " << stream_type.encoding(); |
| codec_id = AV_CODEC_ID_NONE; |
| } |
| |
| AvCodecContextPtr context(avcodec_alloc_context3(nullptr)); |
| |
| context->codec_type = AVMEDIA_TYPE_AUDIO; |
| context->codec_id = codec_id; |
| context->sample_fmt = sample_format; |
| context->channels = stream_type.channels(); |
| context->sample_rate = stream_type.frames_per_second(); |
| |
| if (stream_type.encoding_parameters()) { |
| ExtraDataFromBytes(*stream_type.encoding_parameters(), context); |
| } |
| |
| return context; |
| } |
| |
| // Creats an AVCodecContext from a VideoStreamType. |
| AvCodecContextPtr AVCodecContextFromVideoStreamType(const VideoStreamType& stream_type) { |
| AVCodecID codec_id = AV_CODEC_ID_NONE; |
| |
| if (stream_type.encoding() == StreamType::kVideoEncodingH263) { |
| codec_id = AV_CODEC_ID_H263; |
| } else if (stream_type.encoding() == StreamType::kVideoEncodingH264) { |
| codec_id = AV_CODEC_ID_H264; |
| } else if (stream_type.encoding() == StreamType::kVideoEncodingMpeg4) { |
| codec_id = AV_CODEC_ID_MPEG4; |
| } else if (stream_type.encoding() == StreamType::kVideoEncodingTheora) { |
| codec_id = AV_CODEC_ID_THEORA; |
| } else if (stream_type.encoding() == StreamType::kVideoEncodingVp3) { |
| codec_id = AV_CODEC_ID_VP3; |
| } else if (stream_type.encoding() == StreamType::kVideoEncodingVp8) { |
| codec_id = AV_CODEC_ID_VP8; |
| } else if (stream_type.encoding() == StreamType::kVideoEncodingVp9) { |
| codec_id = AV_CODEC_ID_VP9; |
| } else if (stream_type.encoding() == StreamType::kMediaEncodingUnsupported) { |
| codec_id = AV_CODEC_ID_NONE; |
| } else { |
| FX_LOGS(WARNING) << "unsupported encoding " << stream_type.encoding(); |
| codec_id = AV_CODEC_ID_NONE; |
| } |
| |
| if (codec_id == AV_CODEC_ID_NONE) { |
| return nullptr; |
| } |
| |
| AvCodecContextPtr context(avcodec_alloc_context3(nullptr)); |
| |
| context->codec_type = AVMEDIA_TYPE_VIDEO; |
| context->codec_id = codec_id; |
| context->pix_fmt = AVPixelFormatFromPixelFormat(stream_type.pixel_format()); |
| if (stream_type.color_space() == VideoStreamType::ColorSpace::kJpeg) { |
| context->color_range = AVCOL_RANGE_JPEG; |
| } |
| context->coded_width = stream_type.coded_width(); |
| context->coded_height = stream_type.coded_height(); |
| context->sample_aspect_ratio.num = stream_type.pixel_aspect_ratio_width(); |
| context->sample_aspect_ratio.den = stream_type.pixel_aspect_ratio_height(); |
| |
| if (stream_type.encoding_parameters()) { |
| ExtraDataFromBytes(*stream_type.encoding_parameters(), context); |
| } |
| |
| return context; |
| } |
| |
| // Creats an AVCodecContext from a TextStreamType. |
| AvCodecContextPtr AVCodecContextFromTextStreamType(const TextStreamType& stream_type) { |
| // TODO(dalesat): Implement. |
| FX_LOGS(ERROR) << "AVCodecContextFromTextStreamType not implemented"; |
| abort(); |
| } |
| |
| // Creats an AVCodecContext from a SubpictureStreamType. |
| AvCodecContextPtr AVCodecContextFromSubpictureStreamType(const SubpictureStreamType& stream_type) { |
| // TODO(dalesat): Implement. |
| FX_LOGS(ERROR) << "AVCodecContextFromSupictureStreamType not implemented"; |
| abort(); |
| } |
| |
| } // namespace |
| |
| VideoStreamType::PixelFormat PixelFormatFromAVPixelFormat(AVPixelFormat av_pixel_format) { |
| switch (av_pixel_format) { |
| case AV_PIX_FMT_YUV420P: |
| case AV_PIX_FMT_YUVJ420P: |
| return VideoStreamType::PixelFormat::kYv12; |
| default: |
| return VideoStreamType::PixelFormat::kUnknown; |
| } |
| } |
| |
| AVPixelFormat AVPixelFormatFromPixelFormat(VideoStreamType::PixelFormat pixel_format) { |
| switch (pixel_format) { |
| case VideoStreamType::PixelFormat::kYv12: |
| return AV_PIX_FMT_YUV420P; |
| case VideoStreamType::PixelFormat::kUnknown: |
| case VideoStreamType::PixelFormat::kArgb: |
| case VideoStreamType::PixelFormat::kYuy2: |
| case VideoStreamType::PixelFormat::kNv12: |
| default: |
| return AV_PIX_FMT_NONE; |
| } |
| } |
| |
| // static |
| std::unique_ptr<StreamType> AvCodecContext::GetStreamType(const AVCodecContext& from) { |
| switch (from.codec_type) { |
| case AVMEDIA_TYPE_AUDIO: |
| return StreamTypeFromAudioCodecContext(from); |
| case AVMEDIA_TYPE_VIDEO: |
| return StreamTypeFromVideoCodecContext(from); |
| case AVMEDIA_TYPE_UNKNOWN: |
| // Treated as AVMEDIA_TYPE_DATA. |
| case AVMEDIA_TYPE_DATA: |
| return StreamTypeFromDataCodecContext(from); |
| case AVMEDIA_TYPE_SUBTITLE: |
| return StreamTypeFromSubtitleCodecContext(from); |
| case AVMEDIA_TYPE_ATTACHMENT: |
| case AVMEDIA_TYPE_NB: |
| default: |
| FX_LOGS(ERROR) << "unsupported code type " << from.codec_type; |
| abort(); |
| } |
| } |
| |
| // static |
| std::unique_ptr<StreamType> AvCodecContext::GetStreamType(const AVStream& from) { |
| switch (from.codecpar->codec_type) { |
| case AVMEDIA_TYPE_AUDIO: |
| return StreamTypeFromAudioStream(from); |
| case AVMEDIA_TYPE_VIDEO: |
| return StreamTypeFromVideoStream(from); |
| case AVMEDIA_TYPE_UNKNOWN: |
| // Treated as AVMEDIA_TYPE_DATA. |
| case AVMEDIA_TYPE_DATA: |
| return StreamTypeFromDataCodecParameters(*from.codecpar); |
| case AVMEDIA_TYPE_SUBTITLE: |
| return StreamTypeFromSubtitleCodecParameters(*from.codecpar); |
| case AVMEDIA_TYPE_ATTACHMENT: |
| case AVMEDIA_TYPE_NB: |
| default: |
| FX_LOGS(ERROR) << "unsupported code type " << from.codecpar->codec_type; |
| abort(); |
| } |
| } |
| |
| // static |
| AvCodecContextPtr AvCodecContext::Create(const StreamType& stream_type) { |
| FX_DCHECK(!stream_type.encrypted()); |
| |
| InitFfmpeg(); |
| |
| switch (stream_type.medium()) { |
| case StreamType::Medium::kAudio: |
| return AVCodecContextFromAudioStreamType(*stream_type.audio()); |
| case StreamType::Medium::kVideo: |
| return AVCodecContextFromVideoStreamType(*stream_type.video()); |
| case StreamType::Medium::kText: |
| return AVCodecContextFromTextStreamType(*stream_type.text()); |
| case StreamType::Medium::kSubpicture: |
| return AVCodecContextFromSubpictureStreamType(*stream_type.subpicture()); |
| default: |
| return nullptr; |
| } |
| } |
| |
| } // namespace media_player |