summaryrefslogtreecommitdiffstats
path: root/content/common/gpu/media/vaapi_h264_decoder.h
blob: 3bc63d3b1d94cfe55ab26ca1cc9017ec110c5c0b (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
// 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.
//
// This file contains an implementation of a class that provides H264 decode
// support for use with VAAPI hardware video decode acceleration on Intel
// systems.

#ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_
#define CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_

#include <vector>

#include "base/callback_forward.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/gpu/media/h264_dpb.h"
#include "content/common/gpu/media/h264_parser.h"
#include "content/common/gpu/media/vaapi_wrapper.h"
#include "media/base/limits.h"

namespace content {

// An H264 decoder that utilizes VA-API. Provides features not supported by
// the VA-API userspace library (libva), including stream parsing, reference
// picture management and other operations not supported by the HW codec.
//
// Provides functionality to allow plugging VAAPI HW acceleration into the
// VDA framework.
//
// Clients of this class are expected to pass H264 Annex-B byte stream and
// will receive decoded surfaces via client-provided |OutputPicCB|.
//
// This class must be created, called and destroyed on a single thread, and
// does nothing internally on any other thread.
class VaapiH264Decoder {
 public:
  // Callback invoked on the client when a surface is to be displayed.
  // Arguments: input buffer id provided at the time of Decode()
  // and VASurface to output.
  typedef base::Callback<
      void(int32, const scoped_refptr<VASurface>&)> OutputPicCB;

  enum VAVDAH264DecoderFailure {
    FRAME_MBS_ONLY_FLAG_NOT_ONE = 0,
    GAPS_IN_FRAME_NUM = 1,
    MID_STREAM_RESOLUTION_CHANGE = 2,
    INTERLACED_STREAM = 3,
    VAAPI_ERROR = 4,
    VAVDA_H264_DECODER_FAILURES_MAX,
  };

  // Callback to report errors for UMA purposes, not used to return errors
  // to clients.
  typedef base::Callback<void(VAVDAH264DecoderFailure error)>
      ReportErrorToUmaCB;

  // Decode result codes.
  enum DecResult {
    kDecodeError,  // Error while decoding.
    // TODO posciak: unsupported streams are currently treated as error
    // in decoding; in future it could perhaps be possible to fall back
    // to software decoding instead.
    // kStreamError,  // Error in stream.
    kAllocateNewSurfaces,  // Need a new set of surfaces to be allocated.
    kRanOutOfStreamData,  // Need more stream data to proceed.
    kRanOutOfSurfaces,  // Waiting for the client to free up output surfaces.
  };

  // |vaapi_wrapper| should be initialized.
  // |output_pic_cb| notifies the client a surface is to be displayed.
  // |report_error_to_uma_cb| called on errors for UMA purposes, not used
  // to report errors to clients.
  VaapiH264Decoder(VaapiWrapper* vaapi_wrapper,
                   const OutputPicCB& output_pic_cb,
                   const ReportErrorToUmaCB& report_error_to_uma_cb);

  ~VaapiH264Decoder();

  // Have the decoder flush its state and trigger output of all previously
  // decoded surfaces via OutputPicCB. Return false on failure.
  bool Flush() WARN_UNUSED_RESULT;

  // To be called during decoding.
  // Stop (pause) decoding, discarding all remaining inputs and outputs,
  // but do not flush decoder state, so that the playback can be resumed later,
  // possibly from a different location.
  void Reset();

  // Set current stream data pointer to |ptr| and |size|. Output surfaces
  // that are decoded from data in this stream chunk are to be returned along
  // with the given |input_id|.
  void SetStream(uint8* ptr, size_t size, int32 input_id);

  // Try to decode more of the stream, returning decoded frames asynchronously
  // via output_pic_cb_. Return when more stream is needed, when we run out
  // of free surfaces, when we need a new set of them, or when an error occurs.
  DecResult Decode() WARN_UNUSED_RESULT;

  // Return dimensions/required number of output surfaces that client should
  // be ready to provide for the decoder to function properly.
  // To be used after Decode() returns kNeedNewSurfaces.
  gfx::Size GetPicSize() { return pic_size_; }
  size_t GetRequiredNumOfPictures();

  // To be used by the client to feed decoder with output surfaces.
  void ReuseSurface(const scoped_refptr<VASurface>& va_surface);

 private:
  // We need to keep at most kDPBMaxSize pictures in DPB for
  // reference/to display later and an additional one for the one currently
  // being decoded. We also ask for some additional ones since VDA needs
  // to accumulate a few ready-to-output pictures before it actually starts
  // displaying and giving them back. +2 instead of +1 because of subjective
  // smoothness improvement during testing.
  enum {
    kPicsInPipeline = media::limits::kMaxVideoFrames + 2,
    kMaxNumReqPictures = H264DPB::kDPBMaxSize + kPicsInPipeline,
  };

  // Internal state of the decoder.
  enum State {
    kNeedStreamMetadata,  // After initialization, need an SPS.
    kDecoding,  // Ready to decode from any point.
    kAfterReset, // After Reset(), need a resume point.
    kError,  // Error in decode, can't continue.
  };

  // Process H264 stream structures.
  bool ProcessSPS(int sps_id, bool* need_new_buffers);
  bool ProcessPPS(int pps_id);
  bool ProcessSlice(H264SliceHeader* slice_hdr);

  // Initialize the current picture according to data in |slice_hdr|.
  bool InitCurrPicture(H264SliceHeader* slice_hdr);

  // Calculate picture order counts for the new picture
  // on initialization of a new frame (see spec).
  bool CalculatePicOrderCounts(H264SliceHeader* slice_hdr);

  // Update PicNum values in pictures stored in DPB on creation of new
  // frame (see spec).
  void UpdatePicNums();

  // Prepare reference picture lists (ref_pic_list[01]_).
  bool PrepareRefPicLists(H264SliceHeader* slice_hdr);

  // Construct initial reference picture lists for use in decoding of
  // P and B pictures (see 8.2.4 in spec).
  void ConstructReferencePicListsP(H264SliceHeader* slice_hdr);
  void ConstructReferencePicListsB(H264SliceHeader* slice_hdr);

  // Helper functions for reference list construction, per spec.
  int PicNumF(H264Picture *pic);
  int LongTermPicNumF(H264Picture *pic);

  // Perform the reference picture lists' modification (reordering), as
  // specified in spec (8.2.4).
  //
  // |list| indicates list number and should be either 0 or 1.
  bool ModifyReferencePicList(H264SliceHeader *slice_hdr, int list);

  // Perform reference picture memory management operations (marking/unmarking
  // of reference pictures, long term picture management, discarding, etc.).
  // See 8.2.5 in spec.
  bool HandleMemoryManagementOps();
  void ReferencePictureMarking();

  // Start processing a new frame.
  bool StartNewFrame(H264SliceHeader* slice_hdr);

  // All data for a frame received, process it and decode.
  bool FinishPrevFrameIfPresent();

  // Called after decoding, performs all operations to be done after decoding,
  // including DPB management, reference picture marking and memory management
  // operations.
  // This will also output a picture if one is ready for output.
  bool FinishPicture();

  // Clear DPB contents and remove all surfaces in DPB from *in_use_ list.
  // Cleared pictures will be made available for decode, unless they are
  // at client waiting to be displayed.
  void ClearDPB();

  // These queue up data for HW decoder to be committed on running HW decode.
  bool SendPPS();
  bool SendIQMatrix();
  bool SendVASliceParam(H264SliceHeader* slice_hdr);
  bool SendSliceData(const uint8* ptr, size_t size);
  bool QueueSlice(H264SliceHeader* slice_hdr);

  // Helper methods for filling HW structures.
  void FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic);
  int FillVARefFramesFromDPB(VAPictureH264 *va_pics, int num_pics);

  // Commits all pending data for HW decoder and starts HW decoder.
  bool DecodePicture();

  // Notifies client that a picture is ready for output.
  bool OutputPic(H264Picture* pic);

  // Output all pictures in DPB that have not been outputted yet.
  bool OutputAllRemainingPics();

  // Represents a frame being decoded. Will always have a VASurface
  // assigned to it, which will eventually contain decoded picture data.
  class DecodeSurface;

  // Assign an available surface to the given PicOrderCnt |poc|,
  // removing it from the available surfaces pool. Return true if a surface
  // has been found, false otherwise.
  bool AssignSurfaceToPoC(int32 input_id, int poc);

  // Indicate that a surface is no longer needed by decoder.
  void UnassignSurfaceFromPoC(int poc);

  // Return DecodeSurface assigned to |poc|.
  DecodeSurface* DecodeSurfaceByPoC(int poc);

  // Decoder state.
  State state_;

  // Parser in use.
  H264Parser parser_;

  // DPB in use.
  H264DPB dpb_;

  // Picture currently being processed/decoded.
  scoped_ptr<H264Picture> curr_pic_;

  // Reference picture lists, constructed for each picture before decoding.
  // Those lists are not owners of the pointers (DPB is).
  H264Picture::PtrVector ref_pic_list0_;
  H264Picture::PtrVector ref_pic_list1_;

  // Global state values, needed in decoding. See spec.
  int max_pic_order_cnt_lsb_;
  int max_frame_num_;
  int max_pic_num_;
  int max_long_term_frame_idx_;

  int frame_num_;
  int prev_frame_num_;
  int prev_frame_num_offset_;
  bool prev_has_memmgmnt5_;

  // Values related to previously decoded reference picture.
  bool prev_ref_has_memmgmnt5_;
  int prev_ref_top_field_order_cnt_;
  int prev_ref_pic_order_cnt_msb_;
  int prev_ref_pic_order_cnt_lsb_;
  H264Picture::Field prev_ref_field_;

  // Currently active SPS and PPS.
  int curr_sps_id_;
  int curr_pps_id_;

  // Output picture size.
  gfx::Size pic_size_;

  // Maps H.264 PicOrderCount to currently used DecodeSurfaces;
  typedef std::map<int, linked_ptr<DecodeSurface> > DecSurfacesInUse;
  DecSurfacesInUse decode_surfaces_in_use_;

  // Unused VA surfaces returned by client, ready to be reused.
  std::vector<scoped_refptr<VASurface> > available_va_surfaces_;

  // The id of current input buffer, which will be associated with an
  // output surface when a frame is successfully decoded.
  int32 curr_input_id_;

  VaapiWrapper* vaapi_wrapper_;

  // Called by decoder when a surface should be outputted.
  OutputPicCB output_pic_cb_;

  // Called to report decoding error to UMA, not used to indicate errors
  // to clients.
  ReportErrorToUmaCB report_error_to_uma_cb_;

  // PicOrderCount of the previously outputted frame.
  int last_output_poc_;

  DISALLOW_COPY_AND_ASSIGN(VaapiH264Decoder);
};

}  // namespace content

#endif  // CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_