bool ImageConverter::prepareData() { DPTR_D(ImageConverter); if (d.fmt_out == QTAV_PIX_FMT_C(NONE) || d.w_out <=0 || d.h_out <= 0) return false; AV_ENSURE(av_image_check_size(d.w_out, d.h_out, 0, NULL), false); const int nb_planes = qMax(av_pix_fmt_count_planes(d.fmt_out), 0); d.bits.resize(nb_planes); d.pitchs.resize(nb_planes); // alignment is 16. sws in ffmpeg is 16, libav10 is 8 const int kAlign = 16; AV_ENSURE(av_image_fill_linesizes((int*)d.pitchs.constData(), d.fmt_out, kAlign > 7 ? FFALIGN(d.w_out, 8) : d.w_out), false); for (int i = 0; i < d.pitchs.size(); ++i) d.pitchs[i] = FFALIGN(d.pitchs[i], kAlign); int s = av_image_fill_pointers((uint8_t**)d.bits.constData(), d.fmt_out, d.h_out, NULL, d.pitchs.constData()); if (s < 0) return false; d.data_out.resize(s + kAlign-1); const int offset = (kAlign - ((uintptr_t)d.data_out.constData() & (kAlign-1))) & (kAlign-1); AV_ENSURE(av_image_fill_pointers((uint8_t**)d.bits.constData(), d.fmt_out, d.h_out, (uint8_t*)d.data_out.constData()+offset, d.pitchs.constData()), false); // TODO: special formats //if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) // avpriv_set_systematic_pal2((uint32_t*)pointers[1], pix_fmt); d.update_data = false; for (int i = 0; i < d.pitchs.size(); ++i) { Q_ASSERT(d.pitchs[i]%kAlign == 0); Q_ASSERT(qintptr(d.bits[i])%kAlign == 0); } return true; }
void VideoTransform::convert( const Frame& srcFrame, Frame& dstFrame ) { const VideoFrame& src = static_cast<const VideoFrame&>( srcFrame ); VideoFrame& dst = static_cast<VideoFrame&>( dstFrame ); assert( src.desc().getWidth() != 0 ); assert( src.desc().getHeight() != 0 ); assert( src.desc().getPixelFormat() != AV_PIX_FMT_NONE ); if( ! _isInit ) _isInit = init( srcFrame, dstFrame ); const AVPixelFormat srcPixelFormat = src.desc().getPixelFormat(); const AVPixelFormat dstPixelFormat = dst.desc().getPixelFormat(); // Fill plane data pointers av_image_fill_pointers(&_srcData[0], srcPixelFormat, src.desc().getHeight(), (uint8_t*) src.getData(), &_srcLineSize[0]); av_image_fill_pointers(&_dstData[0], dstPixelFormat, dst.desc().getHeight(), (uint8_t*) dst.getData(), &_dstLineSize[0]); if( ! _imageConvertContext ) { throw std::runtime_error( "unknown color convert context" ); } int ret = sws_scale( _imageConvertContext, &_srcData[0], &_srcLineSize[0], 0, src.desc().getHeight(), &_dstData[0], &_dstLineSize[0] ); if( ret != (int) dst.desc().getHeight() ) throw std::runtime_error( "error in color converter" ); }
static int dxva2_map_frame(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src, int flags) { IDirect3DSurface9 *surface = (IDirect3DSurface9*)src->data[3]; DXVA2Mapping *map; D3DSURFACE_DESC surfaceDesc; D3DLOCKED_RECT LockedRect; HRESULT hr; int i, err, nb_planes; int lock_flags = 0; nb_planes = av_pix_fmt_count_planes(dst->format); hr = IDirect3DSurface9_GetDesc(surface, &surfaceDesc); if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Error getting a surface description\n"); return AVERROR_UNKNOWN; } if (!(flags & AV_HWFRAME_MAP_WRITE)) lock_flags |= D3DLOCK_READONLY; if (flags & AV_HWFRAME_MAP_OVERWRITE) lock_flags |= D3DLOCK_DISCARD; hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL, lock_flags); if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Unable to lock DXVA2 surface\n"); return AVERROR_UNKNOWN; } map = av_mallocz(sizeof(*map)); if (!map) goto fail; err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, dxva2_unmap_frame, map); if (err < 0) { av_freep(&map); goto fail; } for (i = 0; i < nb_planes; i++) dst->linesize[i] = LockedRect.Pitch; av_image_fill_pointers(dst->data, dst->format, surfaceDesc.Height, (uint8_t*)LockedRect.pBits, dst->linesize); if (dst->format == AV_PIX_FMT_PAL8) dst->data[1] = (uint8_t*)map->palette_dummy; return 0; fail: IDirect3DSurface9_UnlockRect(surface); return err; }
static void draw_slice_g200(uint8_t *image[], int stride[], int width,int height,int x,int y) { uint32_t bespitch = FFALIGN(mga_vid_config.src_width, 32); int dst_stride[4] = { bespitch, bespitch }; uint8_t *dst[4]; av_image_fill_pointers(dst, PIX_FMT_NV12, mga_vid_config.src_height, vid_data, dst_stride); sws_scale(sws_ctx, image, stride, y, height, dst, dst_stride); }
static int dxva2_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src) { IDirect3DSurface9 *surface; D3DSURFACE_DESC surfaceDesc; D3DLOCKED_RECT LockedRect; HRESULT hr; uint8_t *surf_data[4] = { NULL }; int surf_linesize[4] = { 0 }; int i; int download = !!src->hw_frames_ctx; surface = (IDirect3DSurface9*)(download ? src->data[3] : dst->data[3]); hr = IDirect3DSurface9_GetDesc(surface, &surfaceDesc); if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Error getting a surface description\n"); return AVERROR_UNKNOWN; } hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL, download ? D3DLOCK_READONLY : D3DLOCK_DISCARD); if (FAILED(hr)) { av_log(ctx, AV_LOG_ERROR, "Unable to lock DXVA2 surface\n"); return AVERROR_UNKNOWN; } for (i = 0; download ? dst->data[i] : src->data[i]; i++) surf_linesize[i] = LockedRect.Pitch; av_image_fill_pointers(surf_data, ctx->sw_format, surfaceDesc.Height, (uint8_t*)LockedRect.pBits, surf_linesize); if (download) { ptrdiff_t src_linesize1[4], dst_linesize1[4]; for (i = 0; i < 4; i++) { dst_linesize1[i] = dst->linesize[i]; src_linesize1[i] = surf_linesize[i]; } av_image_copy_uc_from(dst->data, dst_linesize1, surf_data, src_linesize1, ctx->sw_format, src->width, src->height); } else { av_image_copy(surf_data, surf_linesize, src->data, src->linesize, ctx->sw_format, src->width, src->height); } IDirect3DSurface9_UnlockRect(surface); return 0; }
static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) { FramePool *pool = avctx->internal->pool; int i, ret; switch (avctx->codec_type) { case AVMEDIA_TYPE_VIDEO: { uint8_t *data[4]; int linesize[4]; int size[4] = { 0 }; int w = frame->width; int h = frame->height; int tmpsize, unaligned; if (pool->format == frame->format && pool->width == frame->width && pool->height == frame->height) return 0; avcodec_align_dimensions2(avctx, &w, &h, pool->stride_align); do { // NOTE: do not align linesizes individually, this breaks e.g. assumptions // that linesize[0] == 2*linesize[1] in the MPEG-encoder for 4:2:2 av_image_fill_linesizes(linesize, avctx->pix_fmt, w); // increase alignment of w for next try (rhs gives the lowest bit set in w) w += w & ~(w - 1); unaligned = 0; for (i = 0; i < 4; i++) unaligned |= linesize[i] % pool->stride_align[i]; } while (unaligned); tmpsize = av_image_fill_pointers(data, avctx->pix_fmt, h, NULL, linesize); if (tmpsize < 0) return -1; for (i = 0; i < 3 && data[i + 1]; i++) size[i] = data[i + 1] - data[i]; size[i] = tmpsize - (data[i] - data[0]); for (i = 0; i < 4; i++) { av_buffer_pool_uninit(&pool->pools[i]); pool->linesize[i] = linesize[i]; if (size[i]) { pool->pools[i] = av_buffer_pool_init(size[i] + 16, NULL); if (!pool->pools[i]) { ret = AVERROR(ENOMEM); goto fail; } } } pool->format = frame->format; pool->width = frame->width; pool->height = frame->height; break; } case AVMEDIA_TYPE_AUDIO: { int ch = av_get_channel_layout_nb_channels(frame->channel_layout); int planar = av_sample_fmt_is_planar(frame->format); int planes = planar ? ch : 1; if (pool->format == frame->format && pool->planes == planes && pool->channels == ch && frame->nb_samples == pool->samples) return 0; av_buffer_pool_uninit(&pool->pools[0]); ret = av_samples_get_buffer_size(&pool->linesize[0], ch, frame->nb_samples, frame->format, 0); if (ret < 0) goto fail; pool->pools[0] = av_buffer_pool_init(pool->linesize[0], NULL); if (!pool->pools[0]) { ret = AVERROR(ENOMEM); goto fail; } pool->format = frame->format; pool->planes = planes; pool->channels = ch; pool->samples = frame->nb_samples; break; } default: av_assert0(0); } return 0; fail: for (i = 0; i < 4; i++) av_buffer_pool_uninit(&pool->pools[i]); pool->format = -1; pool->planes = pool->channels = pool->samples = 0; pool->width = pool->height = 0; return ret; }
int FFmpegH264Decoder<LIBAV_VER>::AllocateYUV420PVideoBuffer( AVCodecContext* aCodecContext, AVFrame* aFrame) { bool needAlign = aCodecContext->codec->capabilities & CODEC_CAP_DR1; int edgeWidth = needAlign ? avcodec_get_edge_width() : 0; int decodeWidth = aCodecContext->width + edgeWidth * 2; // Make sure the decodeWidth is a multiple of 32, so a UV plane stride will be // a multiple of 16. FFmpeg uses SSE2 accelerated code to copy a frame line by // line. decodeWidth = (decodeWidth + 31) & ~31; int decodeHeight = aCodecContext->height + edgeWidth * 2; if (needAlign) { // Align width and height to account for CODEC_FLAG_EMU_EDGE. int stride_align[AV_NUM_DATA_POINTERS]; avcodec_align_dimensions2(aCodecContext, &decodeWidth, &decodeHeight, stride_align); } // Get strides for each plane. av_image_fill_linesizes(aFrame->linesize, aCodecContext->pix_fmt, decodeWidth); // Let FFmpeg set up its YUV plane pointers and tell us how much memory we // need. // Note that we're passing |nullptr| here as the base address as we haven't // allocated our image yet. We will adjust |aFrame->data| below. size_t allocSize = av_image_fill_pointers(aFrame->data, aCodecContext->pix_fmt, decodeHeight, nullptr /* base address */, aFrame->linesize); nsRefPtr<Image> image = mImageContainer->CreateImage(ImageFormat::PLANAR_YCBCR); PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image.get()); uint8_t* buffer = ycbcr->AllocateAndGetNewBuffer(allocSize + 64); // FFmpeg requires a 16/32 bytes-aligned buffer, align it on 64 to be safe buffer = reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(buffer) + 63) & ~63); if (!buffer) { NS_WARNING("Failed to allocate buffer for FFmpeg video decoding"); return -1; } // Now that we've allocated our image, we can add its address to the offsets // set by |av_image_fill_pointers| above. We also have to add |edgeWidth| // pixels of padding here. for (uint32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) { // The C planes are half the resolution of the Y plane, so we need to halve // the edge width here. uint32_t planeEdgeWidth = edgeWidth / (i ? 2 : 1); // Add buffer offset, plus a horizontal bar |edgeWidth| pixels high at the // top of the frame, plus |edgeWidth| pixels from the left of the frame. aFrame->data[i] += reinterpret_cast<ptrdiff_t>( buffer + planeEdgeWidth * aFrame->linesize[i] + planeEdgeWidth); } // Unused, but needs to be non-zero to keep ffmpeg happy. aFrame->type = GECKO_FRAME_TYPE; aFrame->extended_data = aFrame->data; aFrame->width = aCodecContext->width; aFrame->height = aCodecContext->height; aFrame->opaque = static_cast<void*>(image.forget().take()); return 0; }
int FFmpegH264Decoder::AllocateYUV420PVideoBuffer(AVCodecContext* aCodecContext, AVFrame* aFrame) { // Older versions of ffmpeg require that edges be allocated* around* the // actual image. int edgeWidth = avcodec_get_edge_width(); int decodeWidth = aCodecContext->width + edgeWidth * 2; int decodeHeight = aCodecContext->height + edgeWidth * 2; // Align width and height to possibly speed up decode. int stride_align[AV_NUM_DATA_POINTERS]; avcodec_align_dimensions2(aCodecContext, &decodeWidth, &decodeHeight, stride_align); // Get strides for each plane. av_image_fill_linesizes(aFrame->linesize, aCodecContext->pix_fmt, decodeWidth); // Let FFmpeg set up its YUV plane pointers and tell us how much memory we // need. // Note that we're passing |nullptr| here as the base address as we haven't // allocated our image yet. We will adjust |aFrame->data| below. size_t allocSize = av_image_fill_pointers(aFrame->data, aCodecContext->pix_fmt, decodeHeight, nullptr /* base address */, aFrame->linesize); nsRefPtr<Image> image = mImageContainer->CreateImage(ImageFormat::PLANAR_YCBCR); PlanarYCbCrImage* ycbcr = reinterpret_cast<PlanarYCbCrImage*>(image.get()); uint8_t* buffer = ycbcr->AllocateAndGetNewBuffer(allocSize); if (!buffer) { NS_WARNING("Failed to allocate buffer for FFmpeg video decoding"); return -1; } // Now that we've allocated our image, we can add its address to the offsets // set by |av_image_fill_pointers| above. We also have to add |edgeWidth| // pixels of padding here. for (uint32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) { // The C planes are half the resolution of the Y plane, so we need to halve // the edge width here. uint32_t planeEdgeWidth = edgeWidth / (i ? 2 : 1); // Add buffer offset, plus a horizontal bar |edgeWidth| pixels high at the // top of the frame, plus |edgeWidth| pixels from the left of the frame. aFrame->data[i] += reinterpret_cast<ptrdiff_t>( buffer + planeEdgeWidth * aFrame->linesize[i] + planeEdgeWidth); } // Unused, but needs to be non-zero to keep ffmpeg happy. aFrame->type = GECKO_FRAME_TYPE; aFrame->extended_data = aFrame->data; aFrame->width = aCodecContext->width; aFrame->height = aCodecContext->height; mozilla::layers::PlanarYCbCrData data; PlanarYCbCrDataFromAVFrame(data, aFrame); ycbcr->SetDataNoCopy(data); mCurrentImage.swap(image); return 0; }
inline CComQIPtr< IDirect3DSurface9 > sl_avframe2surface( CD3D9Device& render, AVFrame* frame ) { bool done = false ; CComQIPtr< IDirect3DSurface9 > surface ; try { if ( render.CreateOffscreenSurface( frame->width, frame->height, sl_map_pixelfmt( frame->format ), &surface ) != 0 ) { throw -1 ; } D3DLOCKED_RECT lr = { 0 } ; if ( surface->LockRect( &lr, nullptr, 0 ) == 0 ) { bool sw_uv = false ; uint8_t* dst_data[ 4 ] = { 0 } ; int dst_linesize[ 4 ] = { 0 } ; switch ( frame->format ) { case AV_PIX_FMT_YUV420P : case AV_PIX_FMT_YUVJ420P : dst_linesize[ 0 ] = lr.Pitch ; dst_linesize[ 1 ] = dst_linesize[ 2 ] = dst_linesize[ 0 ] / 2 ; sw_uv = true ; break ; case AV_PIX_FMT_NV12 : dst_linesize[ 0 ] = dst_linesize[ 1 ] = lr.Pitch ; break ; } if ( dst_linesize[ 0 ] ) { av_image_fill_pointers( dst_data, (AVPixelFormat)frame->format, frame->height, (uint8_t*)lr.pBits, dst_linesize ) ; } if ( dst_data[ 0 ] ) { if ( sw_uv ) { std::swap( dst_data[ 1 ], dst_data[ 2 ] ) ; } av_image_copy( dst_data, dst_linesize, (const uint8_t**)frame->data, frame->linesize, (AVPixelFormat)frame->format, frame->width, frame->height ) ; done = true ; } surface->UnlockRect() ; } } catch ( ... ) { } if ( !done ) { surface.Release() ; } return surface ; }