summaryrefslogtreecommitdiff
path: root/media/cast/video_receiver/codecs/vp8/vp8_decoder.cc
blob: bf56b0a2ad11896d851fd498b95e18de54fe8883 (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
// Copyright 2013 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 "media/cast/video_receiver/codecs/vp8/vp8_decoder.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"

namespace media {
namespace cast {

void LogFrameDecodedEvent(CastEnvironment* const cast_environment,
                          uint32 frame_id) {
// TODO(mikhal): Sort out passing of rtp_timestamp.
// cast_environment->Logging()->InsertFrameEvent(kVideoFrameDecoded,
//      0, frame_id);
}

Vp8Decoder::Vp8Decoder(int number_of_cores,
                       scoped_refptr<CastEnvironment> cast_environment)
    : decoder_(new vpx_dec_ctx_t()),
      cast_environment_(cast_environment) {
  InitDecode(number_of_cores);
}

Vp8Decoder::~Vp8Decoder() {}

void Vp8Decoder::InitDecode(int number_of_cores) {
  vpx_codec_dec_cfg_t  cfg;
  cfg.threads = number_of_cores;
  vpx_codec_flags_t flags = VPX_CODEC_USE_POSTPROC;

  if (vpx_codec_dec_init(decoder_.get(), vpx_codec_vp8_dx(), &cfg, flags)) {
    DCHECK(false) << "VP8 decode error";
  }
}

bool Vp8Decoder::Decode(const EncodedVideoFrame* encoded_frame,
                        const base::TimeTicks render_time,
                        const VideoFrameDecodedCallback& frame_decoded_cb) {
  const int frame_id_int = static_cast<int>(encoded_frame->frame_id);
  VLOG(1) << "VP8 decode frame:" << frame_id_int
          << " sized:" << encoded_frame->data.size();

  if (encoded_frame->data.empty()) return false;

  vpx_codec_iter_t iter = NULL;
  vpx_image_t* img;
  if (vpx_codec_decode(
      decoder_.get(),
      reinterpret_cast<const uint8*>(encoded_frame->data.data()),
      static_cast<unsigned int>(encoded_frame->data.size()),
      0,
      1 /* real time*/)) {
    VLOG(1) << "Failed to decode VP8 frame.";
    return false;
  }

  img = vpx_codec_get_frame(decoder_.get(), &iter);
  if (img == NULL) {
    VLOG(1) << "Skip rendering VP8 frame:" << frame_id_int;
    return false;
  }

  scoped_ptr<I420VideoFrame> decoded_frame(new I420VideoFrame());

  // The img is only valid until the next call to vpx_codec_decode.
  // Populate the decoded image.
  decoded_frame->width = img->d_w;
  decoded_frame->height = img->d_h;

  decoded_frame->y_plane.stride = img->stride[VPX_PLANE_Y];
  decoded_frame->y_plane.length = img->stride[VPX_PLANE_Y] * img->d_h;
  decoded_frame->y_plane.data = new uint8[decoded_frame->y_plane.length];
  memcpy(decoded_frame->y_plane.data, img->planes[VPX_PLANE_Y],
         decoded_frame->y_plane.length);

  decoded_frame->u_plane.stride = img->stride[VPX_PLANE_U];
  decoded_frame->u_plane.length = img->stride[VPX_PLANE_U] * (img->d_h + 1) / 2;
  decoded_frame->u_plane.data = new uint8[decoded_frame->u_plane.length];
  memcpy(decoded_frame->u_plane.data, img->planes[VPX_PLANE_U],
         decoded_frame->u_plane.length);

  decoded_frame->v_plane.stride = img->stride[VPX_PLANE_V];
  decoded_frame->v_plane.length = img->stride[VPX_PLANE_V] * (img->d_h + 1) / 2;
  decoded_frame->v_plane.data = new uint8[decoded_frame->v_plane.length];

  memcpy(decoded_frame->v_plane.data, img->planes[VPX_PLANE_V],
         decoded_frame->v_plane.length);

  // Log:: Decoding complete (should be called from the main thread).
  cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, base::Bind(
      LogFrameDecodedEvent, cast_environment_,encoded_frame->frame_id));
  VLOG(1) << "Decoded frame " << frame_id_int;

  // Frame decoded - return frame to the user via callback.
  cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
      base::Bind(frame_decoded_cb, base::Passed(&decoded_frame),
                 render_time));

  return true;
}

}  // namespace cast
}  // namespace media