FFmpegVideoFramePool.cpp (19972B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "FFmpegVideoFramePool.h" 8 9 #include "FFmpegLog.h" 10 #include "PlatformDecoderModule.h" 11 #include "libavutil/pixfmt.h" 12 #include "mozilla/StaticPrefs_media.h" 13 #include "mozilla/gfx/gfxVars.h" 14 #include "mozilla/widget/DMABufDevice.h" 15 #include "mozilla/widget/va_drmcommon.h" 16 17 // DMABufLibWrapper defines its own version of this which collides with the 18 // official version in drm_fourcc.h 19 #ifdef DRM_FORMAT_MOD_INVALID 20 # undef DRM_FORMAT_MOD_INVALID 21 #endif 22 #include <libdrm/drm_fourcc.h> 23 24 #ifdef MOZ_LOGGING 25 # undef DMABUF_LOG 26 extern mozilla::LazyLogModule gDmabufLog; 27 # define DMABUF_LOG(str, ...) \ 28 MOZ_LOG(gDmabufLog, mozilla::LogLevel::Debug, (str, ##__VA_ARGS__)) 29 #else 30 # define DMABUF_LOG(args) 31 #endif /* MOZ_LOGGING */ 32 33 // Start copying surfaces when free ffmpeg surface count is below 1/4 of all 34 // available surfaces. 35 #define SURFACE_COPY_THRESHOLD (1.0f / 4.0f) 36 37 constexpr static VASurfaceID sInvalidFFMPEGSurfaceID = -1; 38 39 namespace mozilla { 40 41 RefPtr<layers::Image> VideoFrameSurface<LIBAV_VER>::GetAsImage() { 42 return new layers::DMABUFSurfaceImage(mSurface); 43 } 44 45 VideoFrameSurface<LIBAV_VER>::VideoFrameSurface(DMABufSurface* aSurface, 46 VASurfaceID aFFMPEGSurfaceID) 47 : mSurface(aSurface), 48 mLib(nullptr), 49 mAVHWFrameContext(nullptr), 50 mHWAVBuffer(nullptr), 51 mFFMPEGSurfaceID(aFFMPEGSurfaceID), 52 mHoldByFFmpeg(false) { 53 // Create global refcount object to track mSurface usage over 54 // gects rendering engine. We can't release it until it's used 55 // by GL compositor / WebRender. 56 MOZ_ASSERT(mSurface); 57 MOZ_RELEASE_ASSERT(mSurface->GetAsDMABufSurfaceYUV()); 58 mSurface->GlobalRefCountCreate(); 59 DMABUF_LOG("VideoFrameSurface: creating surface UID %d FFmpeg ID %x", 60 mSurface->GetUID(), aFFMPEGSurfaceID); 61 } 62 63 VideoFrameSurface<LIBAV_VER>::~VideoFrameSurface() { 64 DMABUF_LOG("~VideoFrameSurface: deleting dmabuf surface UID %d", 65 mSurface->GetUID()); 66 mSurface->GlobalRefCountDelete(); 67 // We're about to quit, no need to recycle the frames. 68 if (mHoldByFFmpeg) { 69 ReleaseVAAPIData(/* aForFrameRecycle */ false); 70 } 71 } 72 73 void VideoFrameSurface<LIBAV_VER>::DisableRecycle() { 74 MOZ_DIAGNOSTIC_ASSERT(mFFMPEGSurfaceID == sInvalidFFMPEGSurfaceID, 75 "VideoFrameSurface::DisableRecycle(): can't disable " 76 "recycle for FFmpeg surfaces!"); 77 mSurface->DisableRecycle(); 78 } 79 80 void VideoFrameSurface<LIBAV_VER>::LockVAAPIData( 81 AVCodecContext* aAVCodecContext, AVFrame* aAVFrame, 82 const FFmpegLibWrapper* aLib) { 83 mLib = aLib; 84 mHoldByFFmpeg = true; 85 86 // V4L2 frames don't have hw_frames_ctx because the v4l2-wrapper codecs 87 // don't actually use hwaccel. In this case we don't need to add a 88 // HW frame context reference 89 if (aAVCodecContext->hw_frames_ctx) { 90 mAVHWFrameContext = aLib->av_buffer_ref(aAVCodecContext->hw_frames_ctx); 91 mHWAVBuffer = aLib->av_buffer_ref(aAVFrame->buf[0]); 92 DMABUF_LOG( 93 "VideoFrameSurface: VAAPI locking dmabuf surface UID %d FFMPEG ID 0x%x " 94 "mAVHWFrameContext %p mHWAVBuffer %p", 95 mSurface->GetUID(), mFFMPEGSurfaceID, mAVHWFrameContext, mHWAVBuffer); 96 } else { 97 mAVHWFrameContext = nullptr; 98 mHWAVBuffer = aLib->av_buffer_ref(aAVFrame->buf[0]); 99 DMABUF_LOG( 100 "VideoFrameSurface: V4L2 locking dmabuf surface UID %d FFMPEG ID 0x%x " 101 "mHWAVBuffer %p", 102 mSurface->GetUID(), mFFMPEGSurfaceID, mHWAVBuffer); 103 } 104 } 105 106 void VideoFrameSurface<LIBAV_VER>::ReleaseVAAPIData(bool aForFrameRecycle) { 107 DMABUF_LOG( 108 "VideoFrameSurface: Releasing dmabuf surface UID %d FFMPEG ID 0x%x " 109 "aForFrameRecycle %d mLib %p mAVHWFrameContext %p mHWAVBuffer %p", 110 mSurface->GetUID(), mFFMPEGSurfaceID, aForFrameRecycle, mLib, 111 mAVHWFrameContext, mHWAVBuffer); 112 // It's possible to unref GPU data while IsUsedByRenderer() is still set. 113 // It can happen when VideoFramePool is deleted while decoder shutdown 114 // but related dmabuf surfaces are still used in another process. 115 // In such case we don't care as the dmabuf surface will not be 116 // recycled for another frame and stays here untill last fd of it 117 // is closed. 118 if (mLib) { 119 mLib->av_buffer_unref(&mHWAVBuffer); 120 if (mAVHWFrameContext) { 121 mLib->av_buffer_unref(&mAVHWFrameContext); 122 } 123 mLib = nullptr; 124 } 125 126 mHoldByFFmpeg = false; 127 128 // Release dmabuf surface now as we're going to replace it. 129 if (aForFrameRecycle) { 130 mSurface->ReleaseSurface(); 131 } 132 133 if (aForFrameRecycle && IsUsedByRenderer()) { 134 NS_WARNING("Reusing live dmabuf surface, visual glitches ahead"); 135 } 136 } 137 138 VideoFramePool<LIBAV_VER>::VideoFramePool(int aFFMPEGPoolSize) 139 : mSurfaceLock("VideoFramePoolSurfaceLock"), 140 mMaxFFMPEGPoolSize(aFFMPEGPoolSize) { 141 DMABUF_LOG("VideoFramePool::VideoFramePool() pool size %d", 142 mMaxFFMPEGPoolSize); 143 } 144 145 VideoFramePool<LIBAV_VER>::~VideoFramePool() { 146 DMABUF_LOG("VideoFramePool::~VideoFramePool()"); 147 MutexAutoLock lock(mSurfaceLock); 148 mDMABufSurfaces.Clear(); 149 } 150 151 void VideoFramePool<LIBAV_VER>::ReleaseUnusedVAAPIFrames() { 152 MutexAutoLock lock(mSurfaceLock); 153 for (const auto& surface : mDMABufSurfaces) { 154 if (!surface->mHoldByFFmpeg && surface->IsUsedByRenderer()) { 155 DMABUF_LOG("Copied and used surface UID %d", 156 surface->GetDMABufSurface()->GetUID()); 157 } 158 if (surface->mHoldByFFmpeg && !surface->IsUsedByRenderer()) { 159 surface->ReleaseVAAPIData(); 160 } 161 } 162 } 163 164 // Unlink all FFmpeg frames from ID. That ensures we'll allocate new 165 // DMABuf surfaces with fresh UID and we won't recycle old ones. 166 // It's used when FFmpeg invalides frames after avcodec_flush_buffers() call, 167 // before seek for instance. 168 void VideoFramePool<LIBAV_VER>::FlushFFmpegFrames() { 169 MutexAutoLock lock(mSurfaceLock); 170 for (const auto& surface : mDMABufSurfaces) { 171 surface->mFFMPEGSurfaceID = sInvalidFFMPEGSurfaceID; 172 } 173 } 174 175 RefPtr<VideoFrameSurface<LIBAV_VER>> 176 VideoFramePool<LIBAV_VER>::GetFFmpegVideoFrameSurfaceLocked( 177 const MutexAutoLock& aProofOfLock, VASurfaceID aFFMPEGSurfaceID) { 178 MOZ_DIAGNOSTIC_ASSERT( 179 aFFMPEGSurfaceID != sInvalidFFMPEGSurfaceID, 180 "GetFFmpegVideoFrameSurfaceLocked(): expects valid aFFMPEGSurfaceID"); 181 182 // Try to find existing surface by ffmpeg ID. We want to re-use it 183 // to keep matched surface UID / FFmpeg ID. 184 for (auto& surface : mDMABufSurfaces) { 185 if (surface->mFFMPEGSurfaceID == aFFMPEGSurfaceID) { 186 // This should not happen as we reference FFmpeg surfaces from 187 // renderer process. 188 if (surface->IsUsedByRenderer()) { 189 NS_WARNING("Using live surfaces, visual glitches ahead!"); 190 } 191 return surface; 192 } 193 } 194 return nullptr; 195 } 196 197 RefPtr<VideoFrameSurface<LIBAV_VER>> 198 VideoFramePool<LIBAV_VER>::GetFreeVideoFrameSurfaceLocked( 199 const MutexAutoLock& aProofOfLock) { 200 for (auto& surface : mDMABufSurfaces) { 201 if (surface->mFFMPEGSurfaceID != sInvalidFFMPEGSurfaceID) { 202 continue; 203 } 204 if (surface->mHoldByFFmpeg) { 205 continue; 206 } 207 if (surface->IsUsedByRenderer()) { 208 continue; 209 } 210 surface->ReleaseVAAPIData(); 211 return surface; 212 } 213 return nullptr; 214 } 215 216 bool VideoFramePool<LIBAV_VER>::ShouldCopySurface() { 217 // Number of used HW surfaces. 218 int surfacesUsed = 0; 219 int surfacesUsedFFmpeg = 0; 220 for (const auto& surface : mDMABufSurfaces) { 221 if (surface->IsUsedByRenderer()) { 222 surfacesUsed++; 223 if (surface->IsFFMPEGSurface()) { 224 DMABUF_LOG("Used HW surface UID %d FFMPEG ID 0x%x\n", 225 surface->mSurface->GetUID(), surface->mFFMPEGSurfaceID); 226 surfacesUsedFFmpeg++; 227 } 228 } else { 229 if (surface->IsFFMPEGSurface()) { 230 DMABUF_LOG("Free HW surface UID %d FFMPEG ID 0x%x\n", 231 surface->mSurface->GetUID(), surface->mFFMPEGSurfaceID); 232 } 233 } 234 } 235 236 // mMaxFFMPEGPoolSize can be zero for dynamic pools, 237 // we don't do copy in that case unless it's requested by HW setup. 238 float freeRatio = 239 mMaxFFMPEGPoolSize 240 ? 1.0f - (surfacesUsedFFmpeg / (float)mMaxFFMPEGPoolSize) 241 : 1.0; 242 DMABUF_LOG( 243 "Surface pool size %d used copied %d used ffmpeg %d (max %d) free ratio " 244 "%f", 245 (int)mDMABufSurfaces.Length(), surfacesUsed - surfacesUsedFFmpeg, 246 surfacesUsedFFmpeg, mMaxFFMPEGPoolSize, freeRatio); 247 if (!gfx::gfxVars::HwDecodedVideoZeroCopy()) { 248 return true; 249 } 250 return freeRatio < SURFACE_COPY_THRESHOLD; 251 } 252 253 RefPtr<VideoFrameSurface<LIBAV_VER>> 254 VideoFramePool<LIBAV_VER>::GetTargetVideoFrameSurfaceLocked( 255 const MutexAutoLock& aProofOfLock, VASurfaceID aFFmpegSurfaceID, 256 bool aRecycleSurface) { 257 RefPtr<DMABufSurfaceYUV> surface; 258 RefPtr<VideoFrameSurface<LIBAV_VER>> videoSurface; 259 260 // Look for surface pool to select existing or unused surface 261 if (!aRecycleSurface) { 262 // Copied surfaces are not recycled. 263 videoSurface = GetFreeVideoFrameSurfaceLocked(aProofOfLock); 264 } else { 265 // Use FFmpeg ID to find appropriate dmabuf surface. We want to use 266 // the same DMABuf surface for FFmpeg decoded frame (FFmpeg ID). 267 // It allows us to recycle buffers in rendering process. 268 MOZ_DIAGNOSTIC_ASSERT(aFFmpegSurfaceID != sInvalidFFMPEGSurfaceID, 269 "Wrong FFMPEGSurfaceID to recycle!"); 270 videoSurface = 271 GetFFmpegVideoFrameSurfaceLocked(aProofOfLock, aFFmpegSurfaceID); 272 } 273 274 // Okay, create a new one 275 if (!videoSurface) { 276 surface = new DMABufSurfaceYUV(); 277 videoSurface = new VideoFrameSurface<LIBAV_VER>( 278 surface, aRecycleSurface ? aFFmpegSurfaceID : sInvalidFFMPEGSurfaceID); 279 mDMABufSurfaces.AppendElement(videoSurface); 280 DMABUF_LOG("Added new DMABufSurface UID %d", surface->GetUID()); 281 } else { 282 surface = videoSurface->GetDMABufSurface(); 283 DMABUF_LOG("Matched DMABufSurface UID %d", surface->GetUID()); 284 } 285 286 return videoSurface; 287 } 288 289 RefPtr<VideoFrameSurface<LIBAV_VER>> 290 VideoFramePool<LIBAV_VER>::GetVideoFrameSurface( 291 VADRMPRIMESurfaceDescriptor& aVaDesc, int aWidth, int aHeight, 292 AVCodecContext* aAVCodecContext, AVFrame* aAVFrame, 293 const FFmpegLibWrapper* aLib) { 294 if (aVaDesc.fourcc != VA_FOURCC_NV12 && aVaDesc.fourcc != VA_FOURCC_YV12 && 295 aVaDesc.fourcc != VA_FOURCC_P010 && aVaDesc.fourcc != VA_FOURCC_P016) { 296 DMABUF_LOG("Unsupported VA-API surface format %d", aVaDesc.fourcc); 297 return nullptr; 298 } 299 300 MutexAutoLock lock(mSurfaceLock); 301 302 bool copySurface = mTextureCopyWorks && ShouldCopySurface(); 303 304 VASurfaceID ffmpegSurfaceID = (uintptr_t)aAVFrame->data[3]; 305 MOZ_DIAGNOSTIC_ASSERT(ffmpegSurfaceID != sInvalidFFMPEGSurfaceID, 306 "Exported invalid FFmpeg surface ID"); 307 DMABUF_LOG("Got VA-API DMABufSurface FFMPEG ID 0x%x", ffmpegSurfaceID); 308 309 RefPtr<VideoFrameSurface<LIBAV_VER>> videoSurface = 310 GetTargetVideoFrameSurfaceLocked(lock, ffmpegSurfaceID, 311 /* aRecycleSurface */ !copySurface); 312 RefPtr<DMABufSurfaceYUV> surface = videoSurface->GetDMABufSurface(); 313 314 if (!surface->UpdateYUVData(aVaDesc, aWidth, aHeight, copySurface)) { 315 if (!copySurface) { 316 // We failed to move data to DMABuf, so quit now. 317 return nullptr; 318 } 319 320 // We failed to copy data, try again as move. 321 DMABUF_LOG(" DMABuf texture copy is broken"); 322 copySurface = mTextureCopyWorks = false; 323 324 videoSurface = GetTargetVideoFrameSurfaceLocked(lock, ffmpegSurfaceID, 325 /* aRecycleSurface */ true); 326 surface = videoSurface->GetDMABufSurface(); 327 if (!surface->UpdateYUVData(aVaDesc, aWidth, aHeight, 328 /* copySurface */ false)) { 329 return nullptr; 330 } 331 } 332 333 if (MOZ_UNLIKELY(!mTextureCreationWorks)) { 334 mTextureCreationWorks = Some(surface->VerifyTextureCreation()); 335 if (!*mTextureCreationWorks) { 336 DMABUF_LOG(" failed to create texture over DMABuf memory!"); 337 return nullptr; 338 } 339 } 340 341 if (copySurface) { 342 // Disable recycling for copied DMABuf surfaces as we can't ensure 343 // match between FFmpeg frame with DMABufSurface. 344 // It doesn't matter much as surface copy uses extra GPU resources 345 // anyway. 346 videoSurface->DisableRecycle(); 347 } else { 348 videoSurface->LockVAAPIData(aAVCodecContext, aAVFrame, aLib); 349 } 350 351 return videoSurface; 352 } 353 354 static gfx::SurfaceFormat GetSurfaceFormat(enum AVPixelFormat aPixFmt) { 355 switch (aPixFmt) { 356 case AV_PIX_FMT_YUV420P10LE: 357 return gfx::SurfaceFormat::YUV420P10; 358 case AV_PIX_FMT_YUV420P: 359 return gfx::SurfaceFormat::YUV420; 360 default: 361 return gfx::SurfaceFormat::UNKNOWN; 362 } 363 } 364 365 // TODO: Add support for AV_PIX_FMT_YUV444P / AV_PIX_FMT_GBRP 366 RefPtr<VideoFrameSurface<LIBAV_VER>> 367 VideoFramePool<LIBAV_VER>::GetVideoFrameSurface( 368 const layers::PlanarYCbCrData& aData, AVCodecContext* aAVCodecContext) { 369 static gfx::SurfaceFormat format = GetSurfaceFormat(aAVCodecContext->pix_fmt); 370 if (format == gfx::SurfaceFormat::UNKNOWN) { 371 DMABUF_LOG("Unsupported FFmpeg DMABuf format %x", aAVCodecContext->pix_fmt); 372 return nullptr; 373 } 374 375 MutexAutoLock lock(mSurfaceLock); 376 377 RefPtr<VideoFrameSurface<LIBAV_VER>> videoSurface = 378 GetTargetVideoFrameSurfaceLocked(lock, sInvalidFFMPEGSurfaceID, 379 /* aRecycleSurface */ false); 380 RefPtr<DMABufSurfaceYUV> surface = videoSurface->GetDMABufSurface(); 381 382 DMABUF_LOG("Using SW DMABufSurface UID %d", surface->GetUID()); 383 384 if (!surface->UpdateYUVData(aData, format)) { 385 DMABUF_LOG(" failed to convert YUV data to DMABuf memory!"); 386 return nullptr; 387 } 388 389 if (MOZ_UNLIKELY(!mTextureCreationWorks)) { 390 mTextureCreationWorks = Some(surface->VerifyTextureCreation()); 391 if (!*mTextureCreationWorks) { 392 DMABUF_LOG(" failed to create texture over DMABuf memory!"); 393 return nullptr; 394 } 395 } 396 397 // Disable recycling for copied DMABuf surfaces as we can't ensure 398 // match between FFmpeg frame with DMABufSurface. 399 // It doesn't matter much as surface copy/texture upload uses extra 400 // GPU resources anyway. 401 videoSurface->DisableRecycle(); 402 return videoSurface; 403 } 404 405 // Convert an FFmpeg-specific DRM descriptor into a 406 // VADRMPRIMESurfaceDescriptor. There is no fundamental difference between 407 // the descriptor structs and using the latter means this can use all the 408 // existing machinery in DMABufSurfaceYUV. 409 static Maybe<VADRMPRIMESurfaceDescriptor> FFmpegDescToVA( 410 AVDRMFrameDescriptor& aDesc, AVFrame* aAVFrame) { 411 VADRMPRIMESurfaceDescriptor vaDesc{}; 412 413 if (aAVFrame->format != AV_PIX_FMT_DRM_PRIME) { 414 DMABUF_LOG("Got non-DRM-PRIME frame from FFmpeg V4L2"); 415 return Nothing(); 416 } 417 418 if (aAVFrame->crop_top != 0 || aAVFrame->crop_left != 0) { 419 DMABUF_LOG("Top and left-side cropping are not supported"); 420 return Nothing(); 421 } 422 423 // Width and height after crop 424 vaDesc.width = aAVFrame->width; 425 vaDesc.height = aAVFrame->height - aAVFrame->crop_bottom; 426 427 // Native width and height before crop is applied 428 unsigned int uncrop_width = aDesc.layers[0].planes[0].pitch; 429 unsigned int uncrop_height = aAVFrame->height; 430 431 unsigned int offset = aDesc.layers[0].planes[0].offset; 432 433 if (aDesc.layers[0].format == DRM_FORMAT_YUV420) { 434 vaDesc.fourcc = VA_FOURCC_I420; 435 436 // V4L2 expresses YUV420 as a single contiguous buffer containing 437 // all three planes. DMABufSurfaceYUV expects the three planes 438 // separately, so we have to split them out 439 MOZ_ASSERT(aDesc.nb_objects == 1); 440 MOZ_ASSERT(aDesc.nb_layers == 1); 441 442 vaDesc.num_objects = 1; 443 vaDesc.objects[0].drm_format_modifier = aDesc.objects[0].format_modifier; 444 vaDesc.objects[0].size = aDesc.objects[0].size; 445 vaDesc.objects[0].fd = aDesc.objects[0].fd; 446 447 vaDesc.num_layers = 3; 448 for (int i = 0; i < 3; i++) { 449 vaDesc.layers[i].drm_format = DRM_FORMAT_R8; 450 vaDesc.layers[i].num_planes = 1; 451 vaDesc.layers[i].object_index[0] = 0; 452 } 453 vaDesc.layers[0].offset[0] = offset; 454 vaDesc.layers[0].pitch[0] = uncrop_width; 455 vaDesc.layers[1].offset[0] = offset + uncrop_width * uncrop_height; 456 vaDesc.layers[1].pitch[0] = uncrop_width / 2; 457 vaDesc.layers[2].offset[0] = offset + uncrop_width * uncrop_height * 5 / 4; 458 vaDesc.layers[2].pitch[0] = uncrop_width / 2; 459 } else if (aDesc.layers[0].format == DRM_FORMAT_NV12) { 460 vaDesc.fourcc = VA_FOURCC_NV12; 461 462 // V4L2 expresses NV12 as a single contiguous buffer containing both 463 // planes. DMABufSurfaceYUV expects the two planes separately, so we have 464 // to split them out 465 MOZ_ASSERT(aDesc.nb_objects == 1); 466 MOZ_ASSERT(aDesc.nb_layers == 1); 467 468 vaDesc.num_objects = 1; 469 vaDesc.objects[0].drm_format_modifier = aDesc.objects[0].format_modifier; 470 vaDesc.objects[0].size = aDesc.objects[0].size; 471 vaDesc.objects[0].fd = aDesc.objects[0].fd; 472 473 vaDesc.num_layers = 2; 474 for (int i = 0; i < 2; i++) { 475 vaDesc.layers[i].num_planes = 1; 476 vaDesc.layers[i].object_index[0] = 0; 477 vaDesc.layers[i].pitch[0] = uncrop_width; 478 } 479 vaDesc.layers[0].drm_format = DRM_FORMAT_R8; // Y plane 480 vaDesc.layers[0].offset[0] = offset; 481 vaDesc.layers[1].drm_format = DRM_FORMAT_GR88; // UV plane 482 vaDesc.layers[1].offset[0] = offset + uncrop_width * uncrop_height; 483 } else { 484 DMABUF_LOG("Don't know how to deal with FOURCC 0x%x", 485 aDesc.layers[0].format); 486 return Nothing(); 487 } 488 489 return Some(vaDesc); 490 } 491 492 RefPtr<VideoFrameSurface<LIBAV_VER>> 493 VideoFramePool<LIBAV_VER>::GetVideoFrameSurface(AVDRMFrameDescriptor& aDesc, 494 int aWidth, int aHeight, 495 AVCodecContext* aAVCodecContext, 496 AVFrame* aAVFrame, 497 const FFmpegLibWrapper* aLib) { 498 MOZ_ASSERT(aDesc.nb_layers > 0); 499 500 auto layerDesc = FFmpegDescToVA(aDesc, aAVFrame); 501 if (layerDesc.isNothing()) { 502 return nullptr; 503 } 504 505 // Width and height, after cropping 506 int crop_width = (int)layerDesc->width; 507 int crop_height = (int)layerDesc->height; 508 509 MutexAutoLock lock(mSurfaceLock); 510 511 RefPtr<VideoFrameSurface<LIBAV_VER>> videoSurface = 512 GetTargetVideoFrameSurfaceLocked(lock, sInvalidFFMPEGSurfaceID, 513 /* aRecycleSurface */ false); 514 RefPtr<DMABufSurfaceYUV> surface = videoSurface->GetDMABufSurface(); 515 516 DMABUF_LOG("Using V4L2 DMABufSurface UID %d", surface->GetUID()); 517 518 bool copySurface = mTextureCopyWorks && ShouldCopySurface(); 519 if (!surface->UpdateYUVData(layerDesc.value(), crop_width, crop_height, 520 copySurface)) { 521 if (!copySurface) { 522 // Failed without texture copy. We can't do more here. 523 return nullptr; 524 } 525 // Try again without texture copy 526 DMABUF_LOG(" DMABuf texture copy is broken"); 527 copySurface = mTextureCopyWorks = false; 528 if (!surface->UpdateYUVData(layerDesc.value(), crop_width, crop_height, 529 copySurface)) { 530 return nullptr; 531 } 532 } 533 534 if (MOZ_UNLIKELY(!mTextureCreationWorks)) { 535 mTextureCreationWorks = Some(surface->VerifyTextureCreation()); 536 if (!*mTextureCreationWorks) { 537 DMABUF_LOG(" failed to create texture over DMABuf memory!"); 538 return nullptr; 539 } 540 } 541 542 // Don't recycle v4l surfaces, we don't have FFmpegID and we can't ensure 543 // match between FFmpeg frame with DMABufSurface. 544 videoSurface->DisableRecycle(); 545 546 if (!copySurface) { 547 videoSurface->LockVAAPIData(aAVCodecContext, aAVFrame, aLib); 548 } 549 550 return videoSurface; 551 } 552 553 } // namespace mozilla