Index: services/media/framework_ffmpeg/ffmpeg_type_converters.cc |
diff --git a/services/media/framework_ffmpeg/ffmpeg_type_converters.cc b/services/media/framework_ffmpeg/ffmpeg_type_converters.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bc028e4d3f92937d4282c07656a15ef1db034e70 |
--- /dev/null |
+++ b/services/media/framework_ffmpeg/ffmpeg_type_converters.cc |
@@ -0,0 +1,385 @@ |
+// Copyright 2016 The Chromium 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 "base/logging.h" |
+#include "services/media/framework_ffmpeg/ffmpeg_type_converters.h" |
+extern "C" { |
+#include "third_party/ffmpeg/libavformat/avformat.h" |
+} |
+ |
+namespace mojo { |
+namespace media { |
+ |
+namespace { |
+ |
+// Converts an AVSampleFormat into an LpcmStreamType::SampleFormat. |
+LpcmStreamType::SampleFormat Convert(AVSampleFormat av_sample_format) { |
+ switch (av_sample_format) { |
+ case AV_SAMPLE_FMT_U8: |
+ case AV_SAMPLE_FMT_U8P: |
+ return LpcmStreamType::SampleFormat::kUnsigned8; |
+ case AV_SAMPLE_FMT_S16: |
+ case AV_SAMPLE_FMT_S16P: |
+ return LpcmStreamType::SampleFormat::kSigned16; |
+ case AV_SAMPLE_FMT_S32: |
+ case AV_SAMPLE_FMT_S32P: |
+ return LpcmStreamType::SampleFormat::kSigned24In32; |
+ case AV_SAMPLE_FMT_FLT: |
+ case AV_SAMPLE_FMT_FLTP: |
+ return LpcmStreamType::SampleFormat::kFloat; |
+ case AV_SAMPLE_FMT_NONE: |
+ case AV_SAMPLE_FMT_DBL: |
+ case AV_SAMPLE_FMT_DBLP: |
+ case AV_SAMPLE_FMT_NB: |
+ default: |
+ NOTREACHED() << "unsupported av_sample_format " << av_sample_format; |
+ return LpcmStreamType::SampleFormat::kUnknown; |
+ } |
+} |
+ |
+// Copies a buffer from Bytes. The result is malloc'ed and must be freed. |
+uint8_t* ExtraDataFromBytes(const Bytes& bytes, int* byte_count_out) { |
johngro
2016/03/01 01:31:39
This function seems to only be used to populate th
dalesat
2016/03/01 20:43:02
Done.
|
+ size_t byte_count = bytes.size(); |
+ uint8_t* result = reinterpret_cast<uint8_t*>(malloc(byte_count)); |
+ std::memcpy(result, bytes.data(), byte_count); |
+ *byte_count_out = byte_count; |
+ return result; |
+} |
+ |
+// Creates a StreamType from an AVCodecContext describing an LPCM type. |
+std::unique_ptr<StreamType> StreamTypeFromLpcmCodecContext( |
+ AVCodecContext* from) { |
+ return LpcmStreamType::Create( |
+ Convert(from->sample_fmt), |
+ from->channels, |
+ from->sample_rate); |
+} |
+ |
+// Creates a StreamType from an AVCodecContext describing a compressed audio |
+// type. |
+std::unique_ptr<StreamType> |
+StreamTypeFromCompressedAudioCodecContext(AVCodecContext* from) { |
+ CompressedAudioStreamType::AudioEncoding encoding; |
+ switch (from->codec_id) { |
+ case CODEC_ID_VORBIS: |
+ encoding = CompressedAudioStreamType::AudioEncoding::kVorbis; |
+ break; |
+ default: |
+ encoding = CompressedAudioStreamType::AudioEncoding::kUnknown; |
+ break; |
+ } |
+ |
+ return CompressedAudioStreamType::Create( |
+ encoding, |
+ Convert(from->sample_fmt), |
+ from->channels, |
+ from->sample_rate, |
+ from->extradata_size == 0 ? |
+ nullptr : |
+ Bytes::Create(from->extradata, from->extradata_size)); |
+} |
+ |
+// 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; |
+ } |
+} |
+ |
+// Converts VideoProfile to an ffmpeg profile. |
+int FfmpegProfileFromVideoProfile(VideoStreamType::VideoProfile video_profile) { |
+ // TODO(dalesat): Blindly copied from Chromium. |
+ switch (video_profile) { |
+ case VideoStreamType::VideoProfile::kH264Baseline: |
+ return FF_PROFILE_H264_BASELINE; |
+ case VideoStreamType::VideoProfile::kH264Main: |
+ return FF_PROFILE_H264_MAIN; |
+ case VideoStreamType::VideoProfile::kH264Extended: |
+ return FF_PROFILE_H264_EXTENDED; |
+ case VideoStreamType::VideoProfile::kH264High: |
+ return FF_PROFILE_H264_HIGH; |
+ case VideoStreamType::VideoProfile::kH264High10: |
+ return FF_PROFILE_H264_HIGH_10; |
+ case VideoStreamType::VideoProfile::kH264High422: |
+ return FF_PROFILE_H264_HIGH_422; |
+ case VideoStreamType::VideoProfile::kH264High444Predictive: |
+ return FF_PROFILE_H264_HIGH_444_PREDICTIVE; |
+ case VideoStreamType::VideoProfile::kUnknown: |
+ case VideoStreamType::VideoProfile::kNotApplicable: |
+ case VideoStreamType::VideoProfile::kH264ScalableBaseline: |
+ case VideoStreamType::VideoProfile::kH264ScalableHigh: |
+ case VideoStreamType::VideoProfile::kH264StereoHigh: |
+ case VideoStreamType::VideoProfile::kH264MultiviewHigh: |
+ default: |
+ return FF_PROFILE_UNKNOWN; |
+ } |
+} |
+ |
+// Ffmeg defines this...undefine. |
+#undef PixelFormat |
johngro
2016/03/01 01:31:39
oi, global #defs from 3rd party code.
Can we #und
dalesat
2016/03/01 20:43:02
Done.
|
+ |
+// Converts an AVPixelFormat to a PixelFormat. |
+VideoStreamType::PixelFormat PixelFormatFromAVPixelFormat( |
+ AVPixelFormat av_pixel_format) { |
+ // TODO(dalesat): Blindly copied from Chromium. |
+ switch (av_pixel_format) { |
+ case AV_PIX_FMT_YUV422P: |
+ case AV_PIX_FMT_YUVJ422P: |
+ return VideoStreamType::PixelFormat::kYv16; |
+ case AV_PIX_FMT_YUV444P: |
+ case AV_PIX_FMT_YUVJ444P: |
+ return VideoStreamType::PixelFormat::kYv24; |
+ case AV_PIX_FMT_YUV420P: |
+ case AV_PIX_FMT_YUVJ420P: |
+ return VideoStreamType::PixelFormat::kYv12; |
+ case AV_PIX_FMT_YUVA420P: |
+ return VideoStreamType::PixelFormat::kYv12A; |
+ default: |
+ return VideoStreamType::PixelFormat::kUnknown; |
+ } |
+} |
+ |
+// Converts a PixelFormat to an AVPixelFormat. |
+AVPixelFormat AVPixelFormatFromPixelFormat( |
+ VideoStreamType::PixelFormat pixel_format) { |
+ // TODO(dalesat): Blindly copied from Chromium. |
+ switch (pixel_format) { |
+ case VideoStreamType::PixelFormat::kYv12: |
+ return AV_PIX_FMT_YUV420P; |
+ case VideoStreamType::PixelFormat::kYv16: |
+ return AV_PIX_FMT_YUV422P; |
+ case VideoStreamType::PixelFormat::kYv12A: |
+ return AV_PIX_FMT_YUVA420P; |
+ case VideoStreamType::PixelFormat::kYv24: |
+ return AV_PIX_FMT_YUV444P; |
+ case VideoStreamType::PixelFormat::kUnknown: |
+ case VideoStreamType::PixelFormat::kI420: |
+ case VideoStreamType::PixelFormat::kNv12: |
+ case VideoStreamType::PixelFormat::kNv21: |
+ case VideoStreamType::PixelFormat::kUyvy: |
+ case VideoStreamType::PixelFormat::kYuy2: |
+ case VideoStreamType::PixelFormat::kArgb: |
+ case VideoStreamType::PixelFormat::kXrgb: |
+ case VideoStreamType::PixelFormat::kRgb24: |
+ case VideoStreamType::PixelFormat::kRgb32: |
+ case VideoStreamType::PixelFormat::kMjpeg: |
+ case VideoStreamType::PixelFormat::kMt21: |
+ default: |
+ return AV_PIX_FMT_NONE; |
+ } |
+} |
+ |
+// Creates a StreamType from an AVCodecContext describing a video type. |
+std::unique_ptr<StreamType> StreamTypeFromVideoCodecContext( |
+ AVCodecContext* from) { |
+ VideoStreamType::VideoEncoding encoding; |
+ switch (from->codec_id) { |
+ case AV_CODEC_ID_THEORA : |
+ encoding = VideoStreamType::VideoEncoding::kTheora; |
+ break; |
+ case CODEC_ID_VP8: |
+ encoding = VideoStreamType::VideoEncoding::kVp8; |
+ break; |
+ default: |
+ encoding = VideoStreamType::VideoEncoding::kUnknown; |
+ break; |
+ } |
+ |
+ return VideoStreamType::Create( |
+ encoding, |
+ VideoStreamType::VideoProfile::kNotApplicable, |
+ PixelFormatFromAVPixelFormat(from->pix_fmt), |
+ ColorSpaceFromAVColorSpaceAndRange(from->colorspace, from->color_range), |
+ from->width, |
+ from->height, |
+ from->coded_width, |
+ from->coded_height, |
+ from->extradata_size == 0 ? |
+ nullptr : |
+ Bytes::Create(from->extradata, from->extradata_size)); |
+} |
+ |
+// Creates a StreamType from an AVCodecContext describing a data type. |
+std::unique_ptr<StreamType> StreamTypeFromDataCodecContext( |
+ AVCodecContext* from) { |
+ return StreamType::Create(StreamType::Scheme::kUnknown); |
+} |
+ |
+// Creates a StreamType from an AVCodecContext describing a subtitle type. |
+std::unique_ptr<StreamType> StreamTypeFromSubtitleCodecContext( |
+ AVCodecContext* from) { |
+ return StreamType::Create(StreamType::Scheme::kUnknown); |
+} |
+ |
+// Creates an AVCodecContext from LpcmStreamType. |
+AVCodecContext* CodecContextFromLpcmDetails(const LpcmStreamType& stream_type) { |
+ AVCodecID codec_id; |
+ AVSampleFormat sample_format; |
+ |
+ switch (stream_type.sample_format()) { |
+ case LpcmStreamType::SampleFormat::kUnsigned8: |
+ codec_id = AV_CODEC_ID_PCM_U8; |
+ sample_format = AV_SAMPLE_FMT_U8; |
+ break; |
+ case LpcmStreamType::SampleFormat::kSigned16: |
+ codec_id = AV_CODEC_ID_PCM_S16LE; |
+ sample_format = AV_SAMPLE_FMT_S16; |
+ break; |
+ case LpcmStreamType::SampleFormat::kSigned24In32: |
+ codec_id = AV_CODEC_ID_PCM_S24LE; |
+ sample_format = AV_SAMPLE_FMT_S32; |
+ break; |
+ case LpcmStreamType::SampleFormat::kFloat: |
+ codec_id = AV_CODEC_ID_PCM_F32LE; |
+ sample_format = AV_SAMPLE_FMT_FLT; |
+ break; |
+ default: |
+ return nullptr; |
+ } |
+ |
+ AVCodecContext* 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(); |
+ |
+ return context; |
+} |
+ |
+// Creates an AVCodecContext from CompressedAudioStreamType. |
+AVCodecContext* AVCodecContextFromCompressedAudioStreamType( |
+ const CompressedAudioStreamType& stream_type) { |
+ AVCodecID codec_id = AV_CODEC_ID_NONE; |
+ AVSampleFormat sample_format; |
+ |
+ switch (stream_type.encoding()) { |
+ case CompressedAudioStreamType::AudioEncoding::kVorbis: |
+ codec_id = AV_CODEC_ID_VORBIS; |
+ sample_format = AV_SAMPLE_FMT_S16; |
+ break; |
+ default: |
+ return nullptr; |
+ } |
+ |
+ if (codec_id == AV_CODEC_ID_NONE) { |
+ return nullptr; |
+ } |
+ |
+ AVCodecContext* 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_details()) { |
+ context->extradata = ExtraDataFromBytes( |
+ *stream_type.encoding_details(), |
+ &context->extradata_size); |
+ } |
+ |
+ return context; |
+} |
+ |
+// Creats an AVCodecContext from VideoStreamTypeDetails. |
+AVCodecContext* AVCodecContextFromVideoStreamType( |
+ const VideoStreamType& stream_type) { |
+ AVCodecID codec_id = AV_CODEC_ID_NONE; |
+ |
+ // TODO(dalesat): codec_id |
+ |
+ if (codec_id == AV_CODEC_ID_NONE) { |
+ return nullptr; |
+ } |
+ |
+ AVCodecContext* context = avcodec_alloc_context3(nullptr); |
+ |
+ context->codec_type = AVMEDIA_TYPE_VIDEO; |
+ context->codec_id = codec_id; |
+ context->profile = FfmpegProfileFromVideoProfile(stream_type.profile()); |
+ 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(); |
+ |
+ if (stream_type.encoding_details()) { |
+ context->extradata = ExtraDataFromBytes( |
+ *stream_type.encoding_details(), |
+ &context->extradata_size); |
+ } |
+ |
+ return context; |
+} |
+ |
+} // namespace |
+ |
+std::unique_ptr<StreamType> StreamTypeFromAVCodecContext(AVCodecContext* from) { |
+ switch (from->codec_type) { |
+ case AVMEDIA_TYPE_AUDIO: |
+ switch (from->codec_id) { |
+ case CODEC_ID_PCM_S16BE: |
+ case CODEC_ID_PCM_S16LE: |
+ case CODEC_ID_PCM_S24BE: |
+ case CODEC_ID_PCM_S24LE: |
+ case CODEC_ID_PCM_U8: |
+ return StreamTypeFromLpcmCodecContext(from); |
+ default: |
+ if (from->codec == nullptr) { |
+ return StreamTypeFromCompressedAudioCodecContext(from); |
+ } else { |
+ return StreamTypeFromLpcmCodecContext(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: |
+ return StreamType::Create(StreamType::Scheme::kUnknown); |
+ } |
+} |
+ |
+AVCodecContext* AVCodecContextFromStreamType( |
+ const StreamType& stream_type) { |
+ switch (stream_type.scheme()) { |
+ case StreamType::Scheme::kLpcm: |
+ return CodecContextFromLpcmDetails(*stream_type.lpcm()); |
+ case StreamType::Scheme::kCompressedAudio: |
+ return AVCodecContextFromCompressedAudioStreamType( |
+ *stream_type.compressed_audio()); |
+ case StreamType::Scheme::kVideo: |
+ return AVCodecContextFromVideoStreamType(*stream_type.video()); |
+ default: |
+ return nullptr; |
+ } |
+} |
+ |
+} // namespace media |
+} // namespace mojo |