summaryrefslogtreecommitdiff
path: root/chromium/media/base/video_frame.h
blob: b51bfe96d2dc5e94dd066c5c47eb0f3acc0b4b67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
// Copyright (c) 2012 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.

#ifndef MEDIA_BASE_VIDEO_FRAME_H_
#define MEDIA_BASE_VIDEO_FRAME_H_

#include "base/callback.h"
#include "base/md5.h"
#include "base/memory/shared_memory.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "media/base/buffers.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"

class SkBitmap;

namespace media {

class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
 public:
  enum {
    kFrameSizeAlignment = 16,
    kFrameSizePadding = 16,
    kFrameAddressAlignment = 32
  };

  enum {
    kMaxPlanes = 4,

    kYPlane = 0,
    kUPlane = 1,
    kVPlane = 2,
    kAPlane = 3,
  };

  // Surface formats roughly based on FOURCC labels, see:
  // http://www.fourcc.org/rgb.php
  // http://www.fourcc.org/yuv.php
  // Logged to UMA, so never reuse values.
  enum Format {
    UNKNOWN = 0,  // Unknown format value.
    YV12 = 1,  // 12bpp YVU planar 1x1 Y, 2x2 VU samples
    YV16 = 2,  // 16bpp YVU planar 1x1 Y, 2x1 VU samples
    I420 = 3,  // 12bpp YVU planar 1x1 Y, 2x2 UV samples.
    YV12A = 4,  // 20bpp YUVA planar 1x1 Y, 2x2 VU, 1x1 A samples.
#if defined(VIDEO_HOLE)
    HOLE = 5,  // Hole frame.
#endif  // defined(VIDEO_HOLE)
    NATIVE_TEXTURE = 6,  // Native texture.  Pixel-format agnostic.
    YV12J = 7,  // JPEG color range version of YV12
    HISTOGRAM_MAX,  // Must always be greatest.
  };

  // Returns the name of a Format as a string.
  static std::string FormatToString(Format format);

  // This class calls the TextureNoLongerNeededCallback when this class is
  // destroyed.  Users can query the current sync point associated with this
  // mailbox with sync_point(), and should call Resync() with a new sync point
  // to ensure the mailbox remains valid for the issued commands.
  // valid for the issued commands.
  class MEDIA_EXPORT MailboxHolder {
   public:
    typedef base::Callback<void(uint32 sync_point)>
        TextureNoLongerNeededCallback;

    MailboxHolder(const gpu::Mailbox& mailbox,
                  unsigned sync_point,
                  const TextureNoLongerNeededCallback& release_callback);
    ~MailboxHolder();

    const gpu::Mailbox& mailbox() const { return mailbox_; }
    unsigned sync_point() const { return sync_point_; }

    void Resync(unsigned sync_point) { sync_point_ = sync_point; }

   private:

    gpu::Mailbox mailbox_;
    unsigned sync_point_;
    TextureNoLongerNeededCallback release_callback_;
  };


  // Creates a new frame in system memory with given parameters. Buffers for
  // the frame are allocated but not initialized.
  // |coded_size| is the width and height of the frame data in pixels.
  // |visible_rect| is the visible portion of |coded_size|, after cropping (if
  // any) is applied.
  // |natural_size| is the width and height of the frame when the frame's aspect
  // ratio is applied to |visible_rect|.
  static scoped_refptr<VideoFrame> CreateFrame(
      Format format,
      const gfx::Size& coded_size,
      const gfx::Rect& visible_rect,
      const gfx::Size& natural_size,
      base::TimeDelta timestamp);

  // Call prior to CreateFrame to ensure validity of frame configuration. Called
  // automatically by VideoDecoderConfig::IsValidConfig().
  // TODO(scherkus): VideoDecoderConfig shouldn't call this method
  static bool IsValidConfig(Format format, const gfx::Size& coded_size,
                            const gfx::Rect& visible_rect,
                            const gfx::Size& natural_size);

  // CB to write pixels from the texture backing this frame into the
  // |const SkBitmap&| parameter.
  typedef base::Callback<void(const SkBitmap&)> ReadPixelsCB;

  // Wraps a native texture of the given parameters with a VideoFrame.  When the
  // frame is destroyed |no_longer_needed_cb.Run()| will be called.
  // |coded_size| is the width and height of the frame data in pixels.
  // |visible_rect| is the visible portion of |coded_size|, after cropping (if
  // any) is applied.
  // |natural_size| is the width and height of the frame when the frame's aspect
  // ratio is applied to |visible_rect|.

  // |read_pixels_cb| may be used to do (slow!) readbacks from the
  // texture to main memory.
  static scoped_refptr<VideoFrame> WrapNativeTexture(
      scoped_ptr<MailboxHolder> mailbox_holder,
      uint32 texture_target,
      const gfx::Size& coded_size,
      const gfx::Rect& visible_rect,
      const gfx::Size& natural_size,
      base::TimeDelta timestamp,
      const ReadPixelsCB& read_pixels_cb,
      const base::Closure& no_longer_needed_cb);

  // Read pixels from the native texture backing |*this| and write
  // them to |pixels| as BGRA.  |pixels| must point to a buffer at
  // least as large as 4*visible_rect().width()*visible_rect().height().
  void ReadPixelsFromNativeTexture(const SkBitmap& pixels);

  // Wraps packed image data residing in a memory buffer with a VideoFrame.
  // The image data resides in |data| and is assumed to be packed tightly in a
  // buffer of logical dimensions |coded_size| with the appropriate bit depth
  // and plane count as given by |format|.  The shared memory handle of the
  // backing allocation, if present, can be passed in with |handle|.  When the
  // frame is destroyed, |no_longer_needed_cb.Run()| will be called.
  static scoped_refptr<VideoFrame> WrapExternalPackedMemory(
      Format format,
      const gfx::Size& coded_size,
      const gfx::Rect& visible_rect,
      const gfx::Size& natural_size,
      uint8* data,
      size_t data_size,
      base::SharedMemoryHandle handle,
      base::TimeDelta timestamp,
      const base::Closure& no_longer_needed_cb);

  // Wraps external YUV data of the given parameters with a VideoFrame.
  // The returned VideoFrame does not own the data passed in. When the frame
  // is destroyed |no_longer_needed_cb.Run()| will be called.
  // TODO(sheu): merge this into WrapExternalSharedMemory().
  // http://crbug.com/270217
  static scoped_refptr<VideoFrame> WrapExternalYuvData(
      Format format,
      const gfx::Size& coded_size,
      const gfx::Rect& visible_rect,
      const gfx::Size& natural_size,
      int32 y_stride,
      int32 u_stride,
      int32 v_stride,
      uint8* y_data,
      uint8* u_data,
      uint8* v_data,
      base::TimeDelta timestamp,
      const base::Closure& no_longer_needed_cb);

  // Wraps |frame| and calls |no_longer_needed_cb| when the wrapper VideoFrame
  // gets destroyed.
  static scoped_refptr<VideoFrame> WrapVideoFrame(
      const scoped_refptr<VideoFrame>& frame,
      const base::Closure& no_longer_needed_cb);

  // Creates a frame which indicates end-of-stream.
  static scoped_refptr<VideoFrame> CreateEOSFrame();

  // Allocates YV12 frame based on |size|, and sets its data to the YUV(y,u,v).
  static scoped_refptr<VideoFrame> CreateColorFrame(
      const gfx::Size& size,
      uint8 y, uint8 u, uint8 v,
      base::TimeDelta timestamp);

  // Allocates YV12 frame based on |size|, and sets its data to the YUV
  // equivalent of RGB(0,0,0).
  static scoped_refptr<VideoFrame> CreateBlackFrame(const gfx::Size& size);

#if defined(VIDEO_HOLE)
  // Allocates a hole frame.
  static scoped_refptr<VideoFrame> CreateHoleFrame(const gfx::Size& size);
#endif  // defined(VIDEO_HOLE)

  static size_t NumPlanes(Format format);

  // Returns the required allocation size for a (tightly packed) frame of the
  // given coded size and format.
  static size_t AllocationSize(Format format, const gfx::Size& coded_size);

  // Returns the required allocation size for a (tightly packed) plane of the
  // given coded size and format.
  static size_t PlaneAllocationSize(Format format,
                                    size_t plane,
                                    const gfx::Size& coded_size);

  Format format() const { return format_; }

  const gfx::Size& coded_size() const { return coded_size_; }
  const gfx::Rect& visible_rect() const { return visible_rect_; }
  const gfx::Size& natural_size() const { return natural_size_; }

  int stride(size_t plane) const;

  // Returns the number of bytes per row and number of rows for a given plane.
  //
  // As opposed to stride(), row_bytes() refers to the bytes representing
  // frame data scanlines (coded_size.width() pixels, without stride padding).
  int row_bytes(size_t plane) const;
  int rows(size_t plane) const;

  // Returns pointer to the buffer for a given plane. The memory is owned by
  // VideoFrame object and must not be freed by the caller.
  uint8* data(size_t plane) const;

  // Returns the mailbox of the native texture wrapped by this frame. Only
  // valid to call if this is a NATIVE_TEXTURE frame. Before using the
  // mailbox, the caller must wait for the included sync point.
  MailboxHolder* texture_mailbox() const;

  // Returns the texture target. Only valid for NATIVE_TEXTURE frames.
  uint32 texture_target() const;

  // Returns the shared-memory handle, if present
  base::SharedMemoryHandle shared_memory_handle() const;

  // Returns true if this VideoFrame represents the end of the stream.
  bool end_of_stream() const { return end_of_stream_; }

  base::TimeDelta GetTimestamp() const {
    return timestamp_;
  }
  void SetTimestamp(const base::TimeDelta& timestamp) {
    timestamp_ = timestamp;
  }

  // Used to keep a running hash of seen frames.  Expects an initialized MD5
  // context.  Calls MD5Update with the context and the contents of the frame.
  void HashFrameForTesting(base::MD5Context* context);

 private:
  friend class base::RefCountedThreadSafe<VideoFrame>;
  // Clients must use the static CreateFrame() method to create a new frame.
  VideoFrame(Format format,
             const gfx::Size& coded_size,
             const gfx::Rect& visible_rect,
             const gfx::Size& natural_size,
             base::TimeDelta timestamp,
             bool end_of_stream);
  virtual ~VideoFrame();

  void AllocateYUV();

  // Used to DCHECK() plane parameters.
  bool IsValidPlane(size_t plane) const;

  // Frame format.
  Format format_;

  // Width and height of the video frame.
  gfx::Size coded_size_;

  // Width, height, and offsets of the visible portion of the video frame.
  gfx::Rect visible_rect_;

  // Width and height of the visible portion of the video frame with aspect
  // ratio taken into account.
  gfx::Size natural_size_;

  // Array of strides for each plane, typically greater or equal to the width
  // of the surface divided by the horizontal sampling period.  Note that
  // strides can be negative.
  int32 strides_[kMaxPlanes];

  // Array of data pointers to each plane.
  uint8* data_[kMaxPlanes];

  // Native texture mailbox, if this is a NATIVE_TEXTURE frame.
  scoped_ptr<MailboxHolder> texture_mailbox_holder_;
  uint32 texture_target_;
  ReadPixelsCB read_pixels_cb_;

  // Shared memory handle, if this frame was allocated from shared memory.
  base::SharedMemoryHandle shared_memory_handle_;

  base::Closure no_longer_needed_cb_;

  base::TimeDelta timestamp_;

  const bool end_of_stream_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(VideoFrame);
};

}  // namespace media

#endif  // MEDIA_BASE_VIDEO_FRAME_H_