Shaka Player Embedded
ffmpeg_decoded_frame.cc
Go to the documentation of this file.
1 // Copyright 2017 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <glog/logging.h>
18 
19 extern "C" {
20 #include <libavutil/imgutils.h>
21 }
22 
23 namespace shaka {
24 namespace media {
25 namespace ffmpeg {
26 
27 namespace {
28 
29 bool MapFrameFormat(bool is_video, AVFrame* frame,
31  if (is_video) {
32  switch (frame->format) {
33  case AV_PIX_FMT_YUV420P:
34  *format = PixelFormat::YUV420P;
35  return true;
36  case AV_PIX_FMT_NV12:
37  *format = PixelFormat::NV12;
38  return true;
39  case AV_PIX_FMT_RGB24:
40  *format = PixelFormat::RGB24;
41  return true;
42 
43  case AV_PIX_FMT_VIDEOTOOLBOX:
44  *format = PixelFormat::VideoToolbox;
45  return true;
46 
47  default:
48  LOG(DFATAL) << "Unknown pixel format: "
49  << av_get_pix_fmt_name(
50  static_cast<AVPixelFormat>(frame->format));
51  return false;
52  }
53  } else {
54  switch (frame->format) {
55  case AV_SAMPLE_FMT_U8:
56  *format = SampleFormat::PackedU8;
57  return true;
58  case AV_SAMPLE_FMT_S16:
59  *format = SampleFormat::PackedS16;
60  return true;
61  case AV_SAMPLE_FMT_S32:
62  *format = SampleFormat::PackedS32;
63  return true;
64  case AV_SAMPLE_FMT_S64:
65  *format = SampleFormat::PackedS64;
66  return true;
67  case AV_SAMPLE_FMT_FLT:
68  *format = SampleFormat::PackedFloat;
69  return true;
70  case AV_SAMPLE_FMT_DBL:
72  return true;
73 
74  case AV_SAMPLE_FMT_U8P:
75  *format = SampleFormat::PlanarU8;
76  return true;
77  case AV_SAMPLE_FMT_S16P:
78  *format = SampleFormat::PlanarS16;
79  return true;
80  case AV_SAMPLE_FMT_S32P:
81  *format = SampleFormat::PlanarS32;
82  return true;
83  case AV_SAMPLE_FMT_S64P:
84  *format = SampleFormat::PlanarS64;
85  return true;
86  case AV_SAMPLE_FMT_FLTP:
87  *format = SampleFormat::PlanarFloat;
88  return true;
89  case AV_SAMPLE_FMT_DBLP:
91  return true;
92 
93  default:
94  LOG(DFATAL) << "Unknown sample format: "
95  << av_get_sample_fmt_name(
96  static_cast<AVSampleFormat>(frame->format));
97  return false;
98  }
99  }
100 }
101 
102 } // namespace
103 
104 FFmpegDecodedFrame::FFmpegDecodedFrame(
105  AVFrame* frame, double pts, double dts, double duration,
106  std::shared_ptr<const StreamInfo> stream,
108  const std::vector<const uint8_t*>& data,
109  const std::vector<size_t>& linesize)
110  : DecodedFrame(stream, pts, dts, duration, format, frame->nb_samples, data,
111  linesize),
112  frame_(frame) {}
113 
115  av_frame_unref(frame_);
116  av_frame_free(&frame_);
117 }
118 
119 // static
121  std::shared_ptr<const StreamInfo> info, AVFrame* frame, double time,
122  double duration) {
124  if (!MapFrameFormat(info->is_video, frame, &format))
125  return nullptr;
126 
127  std::vector<const uint8_t*> data;
128  std::vector<size_t> linesize;
129  if (info->is_video && get<PixelFormat>(format) == PixelFormat::VideoToolbox) {
130  data.emplace_back(frame->data[3]);
131  linesize.emplace_back(0);
132  } else {
133  const size_t count = GetPlaneCount(format, frame->channels);
134  data.assign(frame->extended_data, frame->extended_data + count);
135  if (info->is_video) {
136  DCHECK_LE(count, sizeof(frame->linesize) / sizeof(frame->linesize[0]));
137  for (size_t i = 0; i < count; i++) {
138  if (frame->linesize[i] < 0) {
139  LOG(DFATAL) << "Negative linesize not supported";
140  return nullptr;
141  }
142  linesize.emplace_back(frame->linesize[i]);
143  }
144  } else {
145  // All audio planes must be the same size.
146  linesize.insert(linesize.end(), count, frame->linesize[0]);
147  }
148  }
149 
150  // TODO(modmaker): Add an AVFrame pool to reuse objects.
151  AVFrame* copy = av_frame_clone(frame);
152  if (!copy)
153  return nullptr;
154  return new (std::nothrow) FFmpegDecodedFrame(copy, time, time, duration, info,
155  format, data, linesize);
156 }
157 
159  size_t size = sizeof(*this) + sizeof(*frame_);
160  for (int i = AV_NUM_DATA_POINTERS; i; i--) {
161  if (frame_->buf[i - 1])
162  size += frame_->buf[i - 1]->size;
163  }
164  for (int i = frame_->nb_extended_buf; i; i--)
165  size += frame_->extended_buf[i - 1]->size;
166  for (int i = frame_->nb_side_data; i; i--)
167  size += frame_->side_data[i - 1]->size;
168  return size;
169 }
170 
171 } // namespace ffmpeg
172 } // namespace media
173 } // namespace shaka
static FFmpegDecodedFrame * CreateFrame(std::shared_ptr< const StreamInfo > stream, AVFrame *frame, double time, double duration)
const std::vector< size_t > linesize
Definition: frames.h:322
std::shared_ptr< shaka::media::DecodedFrame > frame
const std::vector< const uint8_t * > data
Definition: frames.h:312
const variant< PixelFormat, SampleFormat > format
Definition: frames.h:325
size_t GetPlaneCount(variant< PixelFormat, SampleFormat > format, size_t channels)
Definition: frames.cc:92