mirror of
https://github.com/mpv-player/mpv
synced 2025-03-24 12:22:25 +00:00
vd_lavc: add DR1 support
Replace libavcodec's native buffer allocation with code taken from ffplay/ffmpeg's libavfilter support. The code in lavc_dr1.c is directly copied from cmdutils.c. Note that this is quite arcane code, which contains some workarounds for decoder bugs and the like. This is not really a maintainance burden, since fixes from ffmpeg can be directly applied to the code in lavc_dr1.c. It's unknown why libavcodec doesn't provide such a function directly. avcodec_default_get_buffer() can't be reused for various reasons. There's some hope that the work known as The Evil Plan [1] will make custom get_buffer implementations unneeded. The DR1 support as of this commit does nothing. A future commit will use it to implement ref-counting for mp_image (similar to how AVFrame will be ref-counted with The Evil Plan.) [1] http://lists.libav.org/pipermail/libav-devel/2012-December/039781.html
This commit is contained in:
parent
58d196c07e
commit
a8e69707f7
1
Makefile
1
Makefile
@ -229,6 +229,7 @@ SOURCES = talloc.c \
|
||||
video/mp_image.c \
|
||||
video/sws_utils.c \
|
||||
video/decode/dec_video.c \
|
||||
video/decode/lavc_dr1.c \
|
||||
video/decode/vd.c \
|
||||
video/decode/vd_lavc.c \
|
||||
video/filter/vf.c \
|
||||
|
41
video/decode/lavc.h
Normal file
41
video/decode/lavc.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef MPV_LAVC_H
|
||||
#define MPV_LAVC_H
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
#include "demux/stheader.h"
|
||||
#include "video/mp_image.h"
|
||||
|
||||
#define MAX_NUM_MPI 50
|
||||
|
||||
typedef struct ffmpeg_ctx {
|
||||
AVCodecContext *avctx;
|
||||
AVFrame *pic;
|
||||
struct mp_image export_mpi;
|
||||
struct mp_image hwdec_mpi[MAX_NUM_MPI];
|
||||
struct hwdec *hwdec;
|
||||
enum PixelFormat pix_fmt;
|
||||
int do_dr1;
|
||||
int vo_initialized;
|
||||
int best_csp;
|
||||
int qp_stat[32];
|
||||
double qp_sum;
|
||||
double inv_qp_sum;
|
||||
AVRational last_sample_aspect_ratio;
|
||||
enum AVDiscard skip_frame;
|
||||
int rawvideo_fmt;
|
||||
AVCodec *software_fallback;
|
||||
struct FramePool *dr1_buffer_pool;
|
||||
} vd_ffmpeg_ctx;
|
||||
|
||||
int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame);
|
||||
void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame);
|
||||
|
||||
struct FrameBuffer;
|
||||
|
||||
void mp_buffer_ref(struct FrameBuffer *buffer);
|
||||
void mp_buffer_unref(struct FrameBuffer *buffer);
|
||||
|
||||
void mp_buffer_pool_free(struct FramePool **pool);
|
||||
|
||||
#endif
|
227
video/decode/lavc_dr1.c
Normal file
227
video/decode/lavc_dr1.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Various utilities for command line tools
|
||||
* Copyright (c) 2000-2003 Fabrice Bellard
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/avassert.h>
|
||||
#include <libavutil/mathematics.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavutil/pixdesc.h>
|
||||
|
||||
#include "lavc.h"
|
||||
|
||||
typedef struct FramePool {
|
||||
struct FrameBuffer *list;
|
||||
// used to deal with frames that live past the time the pool should live
|
||||
int dead;
|
||||
int refcount; // number of allocated buffers (not in list)
|
||||
} FramePool;
|
||||
|
||||
typedef struct FrameBuffer {
|
||||
uint8_t *base[4];
|
||||
uint8_t *data[4];
|
||||
int linesize[4];
|
||||
|
||||
int h, w;
|
||||
int pix_fmt;
|
||||
|
||||
int refcount;
|
||||
struct FramePool *pool;
|
||||
struct FrameBuffer *next;
|
||||
} FrameBuffer;
|
||||
|
||||
|
||||
static int alloc_buffer(FramePool *pool, AVCodecContext *s)
|
||||
{
|
||||
const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[s->pix_fmt];
|
||||
FrameBuffer *buf;
|
||||
int i, ret;
|
||||
int pixel_size;
|
||||
int h_chroma_shift, v_chroma_shift;
|
||||
int edge = 32; // XXX should be avcodec_get_edge_width(), but that fails on svq1
|
||||
int w = s->width, h = s->height;
|
||||
|
||||
if (!desc)
|
||||
return AVERROR(EINVAL);
|
||||
pixel_size = desc->comp[0].step_minus1 + 1;
|
||||
|
||||
buf = av_mallocz(sizeof(*buf));
|
||||
if (!buf)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
avcodec_align_dimensions(s, &w, &h);
|
||||
|
||||
if (!(s->flags & CODEC_FLAG_EMU_EDGE)) {
|
||||
w += 2*edge;
|
||||
h += 2*edge;
|
||||
}
|
||||
|
||||
if ((ret = av_image_alloc(buf->base, buf->linesize, w, h,
|
||||
s->pix_fmt, 32)) < 0) {
|
||||
av_freep(&buf);
|
||||
av_log(s, AV_LOG_ERROR, "alloc_buffer: av_image_alloc() failed\n");
|
||||
return ret;
|
||||
}
|
||||
/* XXX this shouldn't be needed, but some tests break without this line
|
||||
* those decoders are buggy and need to be fixed.
|
||||
* the following tests fail:
|
||||
* cdgraphics, ansi, aasc, fraps-v1, qtrle-1bit
|
||||
*/
|
||||
memset(buf->base[0], 128, ret);
|
||||
|
||||
avcodec_get_chroma_sub_sample(s->pix_fmt, &h_chroma_shift, &v_chroma_shift);
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
|
||||
const int h_shift = i==0 ? 0 : h_chroma_shift;
|
||||
const int v_shift = i==0 ? 0 : v_chroma_shift;
|
||||
if ((s->flags & CODEC_FLAG_EMU_EDGE) || !buf->linesize[i] || !buf->base[i])
|
||||
buf->data[i] = buf->base[i];
|
||||
else
|
||||
buf->data[i] = buf->base[i] +
|
||||
FFALIGN((buf->linesize[i]*edge >> v_shift) +
|
||||
(pixel_size*edge >> h_shift), 32);
|
||||
}
|
||||
buf->w = s->width;
|
||||
buf->h = s->height;
|
||||
buf->pix_fmt = s->pix_fmt;
|
||||
buf->pool = pool;
|
||||
|
||||
buf->next = pool->list;
|
||||
pool->list = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame)
|
||||
{
|
||||
sh_video_t *sh = s->opaque;
|
||||
struct ffmpeg_ctx *ctx = sh->context;
|
||||
|
||||
if (!ctx->dr1_buffer_pool) {
|
||||
ctx->dr1_buffer_pool = av_mallocz(sizeof(*ctx->dr1_buffer_pool));
|
||||
if (!ctx->dr1_buffer_pool)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
FramePool *pool = ctx->dr1_buffer_pool;
|
||||
FrameBuffer *buf;
|
||||
int ret, i;
|
||||
|
||||
if(av_image_check_size(s->width, s->height, 0, s) || s->pix_fmt<0) {
|
||||
av_log(s, AV_LOG_ERROR, "codec_get_buffer: image parameters invalid\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!pool->list && (ret = alloc_buffer(pool, s)) < 0)
|
||||
return ret;
|
||||
|
||||
buf = pool->list;
|
||||
if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) {
|
||||
pool->list = buf->next;
|
||||
av_freep(&buf->base[0]);
|
||||
av_free(buf);
|
||||
if ((ret = alloc_buffer(pool, s)) < 0)
|
||||
return ret;
|
||||
buf = pool->list;
|
||||
}
|
||||
av_assert0(!buf->refcount);
|
||||
buf->refcount++;
|
||||
|
||||
pool->list = buf->next;
|
||||
pool->refcount++;
|
||||
|
||||
frame->opaque = buf;
|
||||
frame->type = FF_BUFFER_TYPE_USER;
|
||||
frame->extended_data = frame->data;
|
||||
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(buf->data); i++) {
|
||||
frame->base[i] = buf->base[i]; // XXX h264.c uses base though it shouldn't
|
||||
frame->data[i] = buf->data[i];
|
||||
frame->linesize[i] = buf->linesize[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mp_buffer_ref(struct FrameBuffer *buf)
|
||||
{
|
||||
buf->refcount++;
|
||||
}
|
||||
|
||||
void mp_buffer_unref(struct FrameBuffer *buf)
|
||||
{
|
||||
FramePool *pool = buf->pool;
|
||||
|
||||
av_assert0(pool->refcount > 0);
|
||||
av_assert0(buf->refcount > 0);
|
||||
buf->refcount--;
|
||||
if (!buf->refcount) {
|
||||
FrameBuffer *tmp;
|
||||
for(tmp= pool->list; tmp; tmp= tmp->next)
|
||||
av_assert1(tmp != buf);
|
||||
|
||||
buf->next = pool->list;
|
||||
pool->list = buf;
|
||||
pool->refcount--;
|
||||
}
|
||||
|
||||
if (pool->dead && pool->refcount == 0)
|
||||
mp_buffer_pool_free(&pool);
|
||||
}
|
||||
|
||||
void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame)
|
||||
{
|
||||
FrameBuffer *buf = frame->opaque;
|
||||
int i;
|
||||
|
||||
if(frame->type!=FF_BUFFER_TYPE_USER) {
|
||||
avcodec_default_release_buffer(s, frame);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(frame->data); i++)
|
||||
frame->data[i] = NULL;
|
||||
|
||||
mp_buffer_unref(buf);
|
||||
}
|
||||
|
||||
void mp_buffer_pool_free(struct FramePool **p_pool)
|
||||
{
|
||||
struct FramePool *pool = *p_pool;
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
while (pool->list) {
|
||||
FrameBuffer *buf = pool->list;
|
||||
pool->list = buf->next;
|
||||
av_assert0(buf->refcount == 0);
|
||||
av_freep(&buf->base[0]);
|
||||
av_free(buf);
|
||||
}
|
||||
pool->dead = 1;
|
||||
if (pool->refcount == 0)
|
||||
av_free(pool);
|
||||
|
||||
*p_pool = NULL;
|
||||
}
|
@ -58,32 +58,12 @@ static const vd_info_t info = {
|
||||
};
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "lavc.h"
|
||||
|
||||
#if AVPALETTE_SIZE > 1024
|
||||
#error palette too large, adapt libmpcodecs/vf.c:vf_get_image
|
||||
#endif
|
||||
|
||||
#define MAX_NUM_MPI 50
|
||||
|
||||
typedef struct {
|
||||
AVCodecContext *avctx;
|
||||
AVFrame *pic;
|
||||
struct mp_image export_mpi;
|
||||
struct mp_image hwdec_mpi[MAX_NUM_MPI];
|
||||
struct hwdec *hwdec;
|
||||
enum PixelFormat pix_fmt;
|
||||
int do_dr1;
|
||||
int vo_initialized;
|
||||
int best_csp;
|
||||
int qp_stat[32];
|
||||
double qp_sum;
|
||||
double inv_qp_sum;
|
||||
AVRational last_sample_aspect_ratio;
|
||||
enum AVDiscard skip_frame;
|
||||
int rawvideo_fmt;
|
||||
AVCodec *software_fallback;
|
||||
} vd_ffmpeg_ctx;
|
||||
|
||||
#include "core/m_option.h"
|
||||
|
||||
static int init_avctx(sh_video_t *sh, AVCodec *lavc_codec, struct hwdec *hwdec);
|
||||
@ -350,6 +330,9 @@ static int init_avctx(sh_video_t *sh, AVCodec *lavc_codec, struct hwdec *hwdec)
|
||||
avctx->slice_flags =
|
||||
SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
|
||||
}
|
||||
} else {
|
||||
avctx->get_buffer = mp_codec_get_buffer;
|
||||
avctx->release_buffer = mp_codec_release_buffer;
|
||||
}
|
||||
|
||||
if (avctx->thread_count == 0) {
|
||||
@ -492,6 +475,7 @@ static void uninit_avctx(sh_video_t *sh)
|
||||
|
||||
av_freep(&avctx);
|
||||
avcodec_free_frame(&ctx->pic);
|
||||
mp_buffer_pool_free(&ctx->dr1_buffer_pool);
|
||||
}
|
||||
|
||||
static void uninit(sh_video_t *sh)
|
||||
|
Loading…
Reference in New Issue
Block a user