summaryrefslogtreecommitdiffstats
path: root/content/common/gpu/media/avda_codec_image.cc
blob: b6242a905bc0d929c3bd3a23adab4cbb16b80cc9 (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
// Copyright 2015 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 "content/common/gpu/media/avda_codec_image.h"

#include "content/common/gpu/media/avda_shared_state.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/context_state.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "ui/gl/android/surface_texture.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/scoped_make_current.h"

namespace content {

AVDACodecImage::AVDACodecImage(
    const scoped_refptr<AVDASharedState>& shared_state,
    media::VideoCodecBridge* codec,
    const base::WeakPtr<gpu::gles2::GLES2Decoder>& decoder,
    const scoped_refptr<gfx::SurfaceTexture>& surface_texture)
    : shared_state_(shared_state),
      codec_buffer_index_(-1),
      media_codec_(codec),
      decoder_(decoder),
      surface_texture_(surface_texture),
      detach_surface_texture_on_destruction_(false) {}

AVDACodecImage::~AVDACodecImage() {}

void AVDACodecImage::Destroy(bool have_context) {
  // If the SurfaceTexture is using our texture, then detach from it.
  if (detach_surface_texture_on_destruction_) {
    // We don't really care if we have no context, since it doesn't
    // matter if the texture is destroyed here or not.  As long as the
    // surface texture doesn't try to delete this handle later (after
    // it might have been reused), it's fine.  Somebody else will delete
    // our texture when the picture buffer is destroyed.
    surface_texture_->DetachFromGLContext();
    shared_state_->set_surface_texture_service_id(0);
  }
}

gfx::Size AVDACodecImage::GetSize() {
  return size_;
}

unsigned AVDACodecImage::GetInternalFormat() {
  return GL_RGBA;
}

bool AVDACodecImage::BindTexImage(unsigned target) {
  return false;
}

void AVDACodecImage::ReleaseTexImage(unsigned target) {}

bool AVDACodecImage::CopyTexImage(unsigned target) {
  // Have we bound the SurfaceTexture's texture handle to the active
  // texture unit yet?
  bool bound_texture = false;

  // Attach the surface texture to our GL context if needed.
  if (!shared_state_->surface_texture_service_id()) {
    AttachSurfaceTextureToContext();
    bound_texture = true;
  }

  // Make sure that we have the right image in the front buffer.
  bound_texture |= UpdateSurfaceTexture();

  // Sneakily bind the ST texture handle in the real GL context.
  // If we called UpdateTexImage() to update the ST front buffer, then we can
  // skip this.  Since one draw/frame is the common case, we optimize for it.
  if (!bound_texture)
    glBindTexture(GL_TEXTURE_EXTERNAL_OES,
                  shared_state_->surface_texture_service_id());

  // TODO(liberato): Handle the texture matrix properly.
  // Either we can update the shader with it or we can move all of the logic
  // to updateTexImage() to the right place in the cc to send it to the shader.
  // For now, we just skip it.  crbug.com/530681

  gpu::gles2::TextureManager* texture_manager =
      decoder_->GetContextGroup()->texture_manager();
  gpu::gles2::Texture* texture =
      texture_manager->GetTextureForServiceId(
          shared_state_->surface_texture_service_id());
  if (texture) {
    // By setting image state to UNBOUND instead of COPIED we ensure that
    // CopyTexImage() is called each time the surface texture is used for
    // drawing.
    texture->SetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0, this,
                           gpu::gles2::Texture::UNBOUND);
  }

  return true;
}

bool AVDACodecImage::CopyTexSubImage(unsigned target,
                                     const gfx::Point& offset,
                                     const gfx::Rect& rect) {
  return false;
}

bool AVDACodecImage::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
                                          int z_order,
                                          gfx::OverlayTransform transform,
                                          const gfx::Rect& bounds_rect,
                                          const gfx::RectF& crop_rect) {
  return false;
}

void AVDACodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                                  uint64_t process_tracing_id,
                                  const std::string& dump_name) {}

bool AVDACodecImage::UpdateSurfaceTexture() {
  // Render via the media codec if needed.
  if (codec_buffer_index_ > -1 && media_codec_) {
    // We have been given a codec buffer to render, so render it.
    // We might want to ask the avda to release any buffers that come
    // before us without rendering, just for good measure.  However,
    // to prevent doing lots of work on the drawing path, we skip it.

    // The decoder buffer was still pending.
    // This must be synchronous.
    media_codec_->ReleaseOutputBuffer(codec_buffer_index_, true);

    // Don't bother to check if we're rendered again.
    codec_buffer_index_ = -1;

    // Swap the rendered image to the front.
    surface_texture_->UpdateTexImage();

    // UpdateTexImage() binds the ST's texture.
    return true;
  }

  return false;
}

void AVDACodecImage::SetMediaCodecBufferIndex(int buffer_index) {
  codec_buffer_index_ = buffer_index;
}

int AVDACodecImage::GetMediaCodecBufferIndex() const {
  return codec_buffer_index_;
}

void AVDACodecImage::SetSize(const gfx::Size& size) {
  size_ = size;
}

void AVDACodecImage::SetMediaCodec(media::MediaCodecBridge* codec) {
  media_codec_ = codec;
}

void AVDACodecImage::AttachSurfaceTextureToContext() {
  GLint surface_texture_service_id;
  // Use the PictureBuffer's texture.  We could also generate a new texture
  // here, but cleaning it up is problematic.
  glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &surface_texture_service_id);
  DCHECK(surface_texture_service_id);

  // Attach to our service id.
  glBindTexture(GL_TEXTURE_EXTERNAL_OES, surface_texture_service_id);
  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  // The surface texture is already detached, so just attach it.
  surface_texture_->AttachToGLContext();
  shared_state_->set_surface_texture_service_id(surface_texture_service_id);
  detach_surface_texture_on_destruction_ = true;

  // We do not restore the GL state here.
}

}  // namespace content