vikas soni would like Frank Liberato, Dale Curtis and Eric Karl to review this change.
Implement Video decode path using AImageReader.
Implement a new video decode path using Android Image
Reader API which is available from OREO+. Using android
image reader, both GL and Vulkan textures can be created
from video frames which is the main motivation behind this
new path. Existing SurfaceTexture based path will be the
used for android versions < OREO.
Bug : 838725
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: Ib44ac6128340b1419c2bdcc786e3d9d59614e462
---
M media/gpu/BUILD.gn
M media/gpu/android/avda_picture_buffer_manager.cc
A media/gpu/android/image_reader_gl_owner.cc
A media/gpu/android/image_reader_gl_owner.h
A media/gpu/android/image_reader_gl_owner_unittest.cc
M media/gpu/android/surface_texture_gl_owner.cc
M media/gpu/android/surface_texture_gl_owner.h
M media/gpu/android/texture_owner.cc
M media/gpu/android/texture_owner.h
M media/gpu/android/video_frame_factory_impl.cc
10 files changed, 524 insertions(+), 31 deletions(-)
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
Hi,
Can you please review this new path. I tested this path with a html5 video - https://www.quirksmode.org/html5/videos/big_buck_bunny.webm and it seems to be working. (needed to use this 2 flags -> --enable-features=AImageReaderVideoOutput --disable-features=MojoVideoDecoder)
Defer to frank for review here. It's unfortunate to have to keep WaitForFrameAvailable :(
1 comment:
File media/gpu/android/image_reader_gl_owner.h:
Patch Set #30, Line 47: // Most recently acquired image using image reader. This works like a cached
Always use a blank line to separate comments from code above.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
2 comments:
File media/gpu/android/texture_owner.h:
Patch Set #30, Line 34: scoped_refptr<base::SingleThreadTaskRunner> task_runner();
Hacker style must be inline.
File media/gpu/android/texture_owner.cc:
Patch Set #30, Line 41: } else {
Don't use else after a return.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
just some nits -- i'm still thinking about how it works. will add more comments.
thanks
-fl
8 comments:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #30, Line 41: void Signal(void* context, AImageReader* reader) {
this, and probably the whole FrameAvailableEvent_ImageReader, should go into an anonymous namespace.
Patch Set #30, Line 77: listner_
s/listner_/listener_/
Patch Set #30, Line 139: if (return_code != AMEDIA_OK) {
please consider restructuring this as a switch.
Patch Set #30, Line 149: reasons
please << return_code
"e ("
Patch Set #30, Line 158: loader_.AImage_delete(current_image_);
recommend clearing |current_image_| here just to prevent leaving a now-wild ptr. it'll probably be optimized out anyway, so it's free code health.
Patch Set #30, Line 185: egl_fence->ServerWait();
this concerns me -- i need to think about it a bit.
File media/gpu/android/texture_owner.cc:
Patch Set #30, Line 39: ERROR
seems a little severe, and below.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
2 comments:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #30, Line 143: AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED
is this limit guaranteed to be at least 2? as in, might one need to delete the current image to make room for the new one?
Patch Set #30, Line 158: AImage_delete
what does this do to any EGLImage that was created for the AImage?
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
Patch Set 30:
(1 comment)
Defer to frank for review here. It's unfortunate to have to keep WaitForFrameAvailable :(
Thank you Dale. I am positive that we can definitely improve it if not get rid of it.
I will work on it as a follow up patch once this flow is working.
13 comments:
Always use a blank line to separate comments from code above.
Done
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #30, Line 41: // This callback function will be called when there is a new image available for
this, and probably the whole FrameAvailableEvent_ImageReader, should go into an anonymous namespace.
Added this function to anonymous namespace.
FrameAvailable* is used in the header file also. So we cant put it in anonymous namespace.
Patch Set #30, Line 77: DCHECK(r
s/listner_/listener_/
sorry i couldn't get what u meant :( .
Patch Set #30, Line 139: // Acquire the latest image asynchronously
please consider restructuring this as a switch.
Done
Patch Set #30, Line 143: Reader_acquireLatestImageAsync(
is this limit guaranteed to be at least 2? as in, might one need to delete the current image to mak […]
So this limit is set when we create the image reader. Minimum number of images is 2 to support image reader. We can use more number of images as well. For our current requirement to match legacy path, 2 sounded enough.
whenever i acquire a new image, i delete the previous one and hence there is only 1 image acquired at any point.
please << return_code
actually the api AImageReader_acquireLatestImageAsync returns a fix return code AMEDIA_ERROR_UNKNOWN for this error. So we do not need return_code as its known.
it will be more clear in switch statement which i will be using.
"e ("
Done
Patch Set #30, Line 158: return;
recommend clearing |current_image_| here just to prevent leaving a now-wild ptr. […]
Done
what does this do to any EGLImage that was created for the AImage?
So once an EGL image is created using this AImage and is bound to the texture, we can delete the EGL image and its associated AImage. After reading the khronos website about egl image, it seemed like we can delete the source object (egl image and associated resources) once a target object (texture object) is created.
Below is the text from Khronos website:
Once an EGLImage is created from an EGLImage source, the memory associated
with the EGLImage source will remain allocated (and all EGLImage siblings
in all client API contexts will be useable) as long as either of the
following conditions is true:
A) Any EGLImage siblings (texture object) exist in any client API context
B) The EGLImage object exists inside EGL
Patch Set #30, Line 185: // ready to be used immediately. Else we need to create a sync fence which is
this concerns me -- i need to think about it a bit.
Patch Set #30, Line 34: scoped_refptr<base::SingleThreadTaskRunner> task_runner() {
Hacker style must be inline.
seems a little severe, and below.
Done
Don't use else after a return.
Done
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
A few more comments. I think it might be worth following up a bit to confirm the exact behavior of AImageReader.
5 comments:
Patch Set #30, Line 41: // This callback function will be called when there is a new image available for
Added this function to anonymous namespace. […]
since FrameAvailableEvent_ImageReader has to stay in media namespace, maybe it's best just to make Signal a static function?
Patch Set #30, Line 77: DCHECK(r
sorry i couldn't get what u meant :( .
he was just saying you misspelled listener_ (missing an e)
So once an EGL image is created using this AImage and is bound to the texture, we can delete the EGL […]
Note that we immediately delete EGLImages once binding them to a GL texture. As Vikas mentions, the GL texture should keep a reference on the data alive.
That said, people don't always implement the spec perfectly, and this seems a bit tricky. I think I'd prefer if we wait to delete the AImage until the end of this function, where we've overwritten the previous GL texture by binding a new AImage/EGLImage to it.
The one thing that isn't immediately obvious to me is whether we can just delete the image, or whether we should be using AImage_deleteAsync and passing in a fenceFD generated from EGL - I think we may want to use that route, although I'm not sure if this is handled automatically by GL.
vikassoni@, can you follow up with jessehall@ to confirm the behavior here?
This should have a new name so we can look at it independently of the SurfaceTexture path (also, I think this will just confuse UMA). Maybe Media.ImageReaderGLOwner.WaitTimeForFrame?
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #31, Line 163: default
I'd prefer handling all expected cases:
case AMEDIA_OK:
break;
default:
// No other error codes should be returned.
NOTREACHED();
return;
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
6 comments:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #30, Line 41: static void Signal(void* context, AImageReader* reader) {
since FrameAvailableEvent_ImageReader has to stay in media namespace, maybe it's best just to make S […]
I feel that anonymous might be better if we are adding more code in future.
currently its only 1 function, so static vs anonymous might be same. I could be wrong though.
please let me know and i can update.
Patch Set #30, Line 77: listener
he was just saying you misspelled listener_ (missing an e)
Sorry.. Fixed now :)
Patch Set #30, Line 143: der_acquireLatestImageAsync call fai
So this limit is set when we create the image reader. […]
Done
Note that we immediately delete EGLImages once binding them to a GL texture. […]
Talked to jessehall@ and it is clear that when we create EGL image using the AHardwareBuffer associated with the AImage, the EGL image acquires the reference to the buffer and hence we can delete the AImage.
Also once an EGL image is bound to a texture target, GL keeps the associated memory alive until the texture object is destroyed.
Hence we are good here.
Patch Set #30, Line 284: ad_checker_);
This should have a new name so we can look at it independently of the SurfaceTexture path (also, I t […]
I actually renames it to Media.CodecImage.ImageReaderGLOwner.WaitTimeForFrame because now it not only avda codec image but also codec image use in mcvd path.
i will rename the surface texture implementation to Media.CodecImage.SurfaceTextureGLOwner.WaitTimeForFrame
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #31, Line 163: // No
I'd prefer handling all expected cases: […]
Done
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
sorry for the delay on this.
thanks
-fl
2 comments:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #30, Line 143: der_acquireLatestImageAsync call fai
Done
i'm worried that a limit of two won't be supported by all / almost all media codecs. i'm assuming that holding the image here will prevent MC from re-using it, so we're subject to the maximum number of output buffers that it's willing to provide at once.
the lower limit specified in the api is one, if i remember.
i'm okay with trying it this way since it's simpler, but a UMA stat for how often we hit this error is a good idea.
Talked to jessehall@ and it is clear that when we create EGL image using the AHardwareBuffer associa […]
how do these images interact with MC? does MC understand not to overwrite the buffer with a newly decoded frame between the time when we AImage_delete it and the time the EGL image is destroyed?
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
LGTM from my end % Frank's comments, which we should address, and an additional nit.
Patch set 32:Code-Review +1
2 comments:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #30, Line 41: static void Signal(void* context, AImageReader* reader) {
I feel that anonymous might be better if we are adding more code in future. […]
nit: sorry, wasn't clear here - I meant a static member function of FrameAvailableEvent_ImageReader, keeps it more grouped with related code.
Patch Set #30, Line 143: der_acquireLatestImageAsync call fai
i'm worried that a limit of two won't be supported by all / almost all media codecs. […]
+1 to adding an uma.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
2 comments:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #30, Line 143: der_acquireLatestImageAsync call fai
+1 to adding an uma.
Sure i will add UMA. The lower limit for getLatestImage is specified as 2 in the api documentation to work correctly.
how do these images interact with MC? does MC understand not to overwrite the buffer with a newly d […]
Thank u frank for pointing this out. Actually my video playback was working fine and smooth somehow on avda path but frames are shivering on the new mcvd path.
This is because i think i am deleting the image (and hence letting MC know it can overwrite it) without making sure that the corresponding egl image texture is consumed by gpu.
I will need to add a fence command at the point where texture is used and done and signal the completion.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
File media/gpu/android/image_reader_gl_owner.cc:
Thank u frank for pointing this out. […]
Hi Frank,
I need some help from you. So this current code without any sync with gpu is working fine in avda path but shivering in new mcvd path. As u pointed out, most probably the underlying buffer is getting with new data even before previous one is drawn.
So to experiment, i inserted a glfinish() command just before this line where i am deleting the image. This should ensure the previous texture is drawn before the image is deleted. But i still get same shivering video. I also tried to use Aimage_deleteAsync() but still the same issue.
I wanted some help/pointers from you on why this might be happening or what is different in the new mcvd path compared to avda one.
Please let me know. Thank you.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Hi Frank, […]
it just so happens that mcvd had a bug that might cause this -- it wasn't properly waiting for sync tokens before reusing a frame. it landed friday (https://chromium-review.googlesource.com/1028550). please try rebasing on top of that, and see if things get better.
now, if this is does make the problem go away, then it raises another question. before the bug fix, mcvd looked okay when using SurfaceTexture but not with AImageReader. why?
mcvd was definitely broken in either case, but it's worth understanding a bit more about how these paths differ here. i can't think of anything that SurfaceTexture could do to help us, if the sync token hasn't cleared and the gl commands for the outgoing texture haven't even been issued yet!
my concern is that something else is also different in the AImageReader case. might be a good or bad difference, but worth understanding in more detail, in my opinion.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
it just so happens that mcvd had a bug that might cause this -- it wasn't properly waiting for sync […]
Ya agree that's true. I will dig into it more.
Also Aimagereader is currently working with avda path but not with mcvd. So i was wondering if u can little bit explain what are the main differences between those two paths so that i can explore it more.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Ya agree that's true. I will dig into it more. […]
Also forgot to mention that updating the code didn't fixes this issue :( .
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Also forgot to mention that updating the code didn't fixes this issue :( .
MCVD creates a new gl texture per frame, while AVDA re-uses a pool of them. other than that, i don't think that there should be a difference.
both use the sync token for synchronization. avda has this done for it by gpu_video_decoder (in the renderer), while mcvd does the wait in the gpu process. it's possible, i suppose, that something is broken sending the most recent sync token from the renderer to gpu via mojo (see MojoVideoDecoder::OnVideoFrameDecoded, which sets the release callback on the VideoFrame. this callback is called with the most recent sync token, which the callback forwards to the gpu process).
the other possibility is that they differ in when they apply an optimization to releasing codec buffers. they each have a notion of "MaybeRenderEarly", which tries to render a media codec output buffer to the back buffer of the surface texture, potentially long before we're ready to swap it to the front buffer via UpdateTexImage. maybe MCVD is being more aggressive, though i'm not sure.
you might try disabling that optimization to see if it helps. see video_frame_factory_impl.cc for the MaybeRenderEarly fn -- just make it do nothing, i think. be sure to get the one in video_frame_factory_impl.cc -- avda has its own MaybeRenderEarly, which does the same thing just not for MCVD. yeah, it'll be removed when AVDA goes away.
if the optimization is the cause, then we'll have to figure out if (a) MCVD is applying it incorrectly, or (b) something in the AImageReader path isn't working right.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
MCVD creates a new gl texture per frame, while AVDA re-uses a pool of them. […]
Disabling the optimization seems to be working. I am stepping through the code to understand more why it is not working for AImageReader and whats in the non-optimized path is making it to work.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Disabling the optimization seems to be working. […]
Hi Frank,
It seems like i found the issue. I was inserting a fence and deleting previously acquired image just before i was going to acquire the next one.
But i guess when i acquire the next image using updateTexImage() call, its not guaranteed that previously acquired image texture is drawn. hence i was creating fence at wrong place.
Do u know at which point i should insert a fence to make sure the texture is drawn and the backing buffer/image can be deleted/released safely.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Hi Frank, […]
UpdateTexImage should be called after all draw commands for the previous frame have been issued, so i'd expect a fence to be sufficient.
it looks like you're waiting on the fence after deleting the image, not before. what if you move the AImageDelete lower, to around @187?
here are some other thoughts i had, probably for a follow-up CL. but, i don't want to forget them:
right now, all the AImage work is deferred until we UpdateTexImage. however, we might be able to move some of it earlier to reduce latency.
when we tell MediaCodec to release a codec buffer to the surface, some of the AImageReader work can begin immediately -- it could try to acquire the new image, without deleting the current front buffer image. that might reduce latency. we'll have to measure it. the whole MaybeRenderEarly thing is because we it makes a difference with higher frame rate videos, especially. i.e., we can play things smoothly that we couldn't before implementing MaybeRenderEarly.
we still have to defer the fence + AImage_delete until UpdateTexImage. we'll need to measure to see where the latency is. SurfaceTexture could be doing this now (don't know), and if so, then the AImage version might regress performance without it.
actually, we might be able to do even better than SurfaceTexture: we could avoid having the fence in UpdateTexImage at all, since we can just keep the back buffer around longer until the pipeline is done with it, independently of signalling that we have a new image for the front buffer. assuming that we can have to images outstanding at once, this might hide a lot of latency!
anyway, that's not for this CL; we'll have to measure performance carefully to make sure AImage is as good as the ST impl, and that will tell us.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
UpdateTexImage should be called after all draw commands for the previous frame have been issued, so […]
So the fence in this patch below is to acquire the image and not for deletion. For deletion i inserted a fence (even tried glFinish()) just before deleting the image. But that doesn't seems to work for MaybeRenderEarly path.
Also i guess if updateTexImage was guaranteed to be called after the draw for previous frame is done, we don't even need a fence and simply deleting previous frame should have been safe. Maybe this is true for non-optimized path as that works fine w/o any fence. For MaybeRenderearly path, i feel like updateTexImage is called for second frame before the draw for first one is done and hence seeing shivering in video.
To solve this currently what i did is to keep a queue of 4 previous images and not delete it. I only start deleting the image once i have acquired maximum number of images and the queue is full. That seems to work without any fence and guarantee that by the time we start deleting/releasing the older images, the draw for it is done. I think this is something you are saying in above comments.
Please let me know what you think. I will upload a patch for u to see.
Also as you have mentioned, for a follow up patch we can simply the design a lot.
Aimagereader already have a queue of images (essentially queue of back buffers).
We can also keep a queue of pre-acquired images(before the UpdateTexImage()) and then just start binding them one by one on updateTexImage call.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #30, Line 158: R) << "AImage
So the fence in this patch below is to acquire the image and not for deletion. […]
Hi Frank,
I talked to @piman regarding the issue i was facing in the optimized path.
He figured out that the optimized path was not doing glBindTexture() and the AImageReader->UpdateTexImage() was also not doing it. and hence we were seeing the issue.
SurfaceTexture->UpdateTexImage() used to do it internally and that's why it is working.
So to fix this issue i added glBindTexture() just before calling a BindTexImage on egl_image.
Now AImageReader path is working for both optimized as well as non-optimised path (of both mojo and avda).
I also added a fence to signal the release of image to make sure the image is drawn before we release it and nothing bad happens.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
looks nice! just nits.
thanks
-fl
6 comments:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #33, Line 143: switch (return_code) {
please add a todo and crbug for error handling here. i'm particularly worried about MAX_IMAGES_ACQUIRED.
Patch Set #33, Line 145: ERROR
you can probably shorten these into one error -- you'll get the filename and line (i think -- maybe check that) automatically, so the context should be fairly clear.
Patch Set #33, Line 171: image
consider restructuring this to be an early return if |!image|.
Patch Set #33, Line 177: GetGpuFence
i don't know much about how chromium's wrapper classes for fences work, so i'm not checking this part. in particular, are we responsible for closing the duplicate handle, or does deleteAsync handle it? the docs were pretty sparse.
|hndl| is pretty terse. |handle| or |fence_handle| or something would be clearer. ditto |gpfc| and |fc|.
Patch Set #33, Line 246: glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
ahhhh! :)
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
Fixed code reviews.
I have also added sparse histogram UMA to collect data when error occurs for acquireLatestImageAsync()
5 comments:
File media/gpu/android/image_reader_gl_owner.cc:
Patch Set #33, Line 143: return_code = loader_.AImageReader_acquireLatestImageAsync(
please add a todo and crbug for error handling here. […]
Done
you can probably shorten these into one error -- you'll get the filename and line (i think -- maybe […]
Done
Patch Set #33, Line 171: se AM
consider restructuring this to be an early return if |!image|.
Done
i don't know much about how chromium's wrapper classes for fences work, so i'm not checking this par […]
The Async calls closes the handle. I actually figured this out because initially i didn't duplicate the handle and then it was getting closed twice and i was running into some crash.
|hndl| is pretty terse. |handle| or |fence_handle| or something would be clearer. […]
Ya sorry about that. i was experimenting initially and forgot to update better names.
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
Hi Frank,
Let me know if everything looks good. I can merge this CL once u give +1.
thanks
sorry for the delay. lgtm.
Patch set 35:Code-Review +1
Awesome. Thank you Frank.
Patch set 35:Commit-Queue +2
Try jobs failed on following builders:
chromium_presubmit on luci.chromium.try (JOB_FAILED, https://ci.chromium.org/p/chromium/builders/luci.chromium.try/chromium_presubmit/123249)
Hi Gayane,
I have modified histogram.xml as I needed to add a sparse histogram for logging some error (which are expected to not occur).
can u please give lgtm if it looks ok.
thank you
Thanks.
1 comment:
File tools/metrics/histograms/histograms.xml:
Patch Set #35, Line 35909: histogram
FYI: Recently we added expires_after field for histograms. You can now use expires_after field to specify the intended lifetime of the histogram. For example, if this histogram is mostly intended to be used during launch of the project which is planned for M69 then you can specify expires_after="M69". You can also use dates, for example, expires_after="2018-09-30".
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
Hi Gayane,
I have added an expiry date. Can you please check and give LGTM if its looks good.
thank you
1 comment:
Patch Set #35, Line 35909: histogram
FYI: Recently we added expires_after field for histograms. […]
Thank you. I have added an expiry date.
Done
To view, visit change 963506. To unsubscribe, or for help writing mail filters, visit settings.
Thanks
Patch set 36:Code-Review +1
Patch set 36:Commit-Queue +2
Commit Bot merged this change.
Implement Video decode path using AImageReader.
Implement a new video decode path using Android Image
Reader API which is available from OREO+. Using android
image reader, both GL and Vulkan textures can be created
from video frames which is the main motivation behind this
new path. Existing SurfaceTexture based path will be the
used for android versions < OREO.
Bug : 838725
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: Ib44ac6128340b1419c2bdcc786e3d9d59614e462
Reviewed-on: https://chromium-review.googlesource.com/963506
Reviewed-by: Gayane Petrosyan <gay...@chromium.org>
Reviewed-by: Frank Liberato <libe...@chromium.org>
Reviewed-by: Eric Karl <eri...@chromium.org>
Commit-Queue: vikas soni <vika...@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561988}
---
M media/gpu/BUILD.gn
M media/gpu/android/android_image_reader_abi.h
M media/gpu/android/android_image_reader_compat.cc
M media/gpu/android/android_image_reader_compat.h
M media/gpu/android/avda_picture_buffer_manager.cc
A media/gpu/android/image_reader_gl_owner.cc
A media/gpu/android/image_reader_gl_owner.h
A media/gpu/android/image_reader_gl_owner_unittest.cc
M media/gpu/android/surface_texture_gl_owner.cc
M media/gpu/android/surface_texture_gl_owner.h
M media/gpu/android/texture_owner.cc
M media/gpu/android/texture_owner.h
M media/gpu/android/video_frame_factory_impl.cc
M tools/metrics/histograms/enums.xml
M tools/metrics/histograms/histograms.xml
15 files changed, 598 insertions(+), 28 deletions(-)