OSDN Git Service

33c84fb8b9ce8bcfe9a479094e63243a191fc4d8
[android-x86/external-stagefright-plugins.git] / omx / ffmpeg_hwaccel.c
1 #define DEBUG_HWACCEL 0
2 #define LOG_TAG "HWACCEL"
3 #include <cutils/log.h>
4 #include <cutils/properties.h>
5
6 #include "config.h"
7 #include "ffmpeg_hwaccel.h"
8 #include "libavutil/hwcontext.h"
9 #include "libavutil/opt.h"
10 #include "libavutil/pixdesc.h"
11 #ifdef LIBAV_CONFIG_H
12 #include "avtools/avconv.h"
13 #else
14 #include "ffmpeg.h"
15 #endif
16
17 /* BEGIN: Extracted from ffmpeg_opt.c */
18
19 const HWAccel hwaccels[] = {
20 #if HAVE_VDPAU_X11
21     { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU },
22 #endif
23 #if CONFIG_VDA
24     { "vda", videotoolbox_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
25 #endif
26 #if CONFIG_LIBMFX
27     { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV },
28 #endif
29 #if CONFIG_VAAPI
30 #ifdef LIBAV_CONFIG_H
31     { "vaapi", hwaccel_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI, AV_HWDEVICE_TYPE_VAAPI },
32 #else
33     { "vaapi", vaapi_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI },
34 #endif
35 #endif
36 #if CONFIG_CUVID
37     { "cuvid", cuvid_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA },
38 #endif
39     { 0, 0, HWACCEL_NONE, AV_PIX_FMT_NONE },
40 };
41
42 /* END: Extracted from ffmpeg_opt.c */
43
44 int ffmpeg_hwaccel_get_frame(AVCodecContext *avctx, AVFrame *frame)
45 {
46     int err;
47     InputStream *ist = avctx->opaque;
48
49     if (ist && ist->hwaccel_retrieve_data && frame->format == ist->hwaccel_pix_fmt) {
50         ALOGV_IF(DEBUG_HWACCEL, "ffmpeg_hwaccel_get_frame ctx=%p ist=%p format=%d hwaccel_pix_fmt=%d hwaccel_id=%d",
51                 avctx, ist, frame->format, ist->hwaccel_pix_fmt, ist->hwaccel_id);
52         err = ist->hwaccel_retrieve_data(avctx, frame);
53         if (err == 0)
54             ist->hwaccel_retrieved_pix_fmt = frame->format;
55     } else {
56         err = 0;
57     }
58
59     return err;
60 }
61
62 /* BEGIN: Extracted from ffmpeg.c */
63
64 static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt)
65 {
66     int i;
67     for (i = 0; hwaccels[i].name; i++)
68         if (hwaccels[i].pix_fmt == pix_fmt)
69             return &hwaccels[i];
70     return NULL;
71 }
72
73 static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
74 {
75     InputStream *ist = s->opaque;
76     const enum AVPixelFormat *p;
77     int ret = -1;
78
79     for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
80         ALOGD_IF(DEBUG_HWACCEL, "check %td pix_fmts=%d", p - pix_fmts, *p);
81         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
82         const HWAccel *hwaccel;
83
84         if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
85             break;
86
87         hwaccel = get_hwaccel(*p);
88         if (!hwaccel ||
89                 (ist->active_hwaccel_id && ist->active_hwaccel_id != hwaccel->id) ||
90                 (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id != hwaccel->id))
91             continue;
92
93         ret = hwaccel->init(s);
94         if (ret < 0) {
95             if (ist->hwaccel_id == hwaccel->id) {
96                 av_log(NULL, AV_LOG_FATAL,
97                        "%s hwaccel requested for input stream #%d, "
98                        "but cannot be initialized.\n", hwaccel->name, ist->file_index);
99             }
100             continue;
101         }
102         if (ist->hw_frames_ctx) {
103             s->hw_frames_ctx = av_buffer_ref(ist->hw_frames_ctx);
104             if (!s->hw_frames_ctx)
105                 return AV_PIX_FMT_NONE;
106         }
107         ist->active_hwaccel_id = hwaccel->id;
108         ist->hwaccel_pix_fmt = *p;
109         s->thread_count = 1;
110 #ifdef LIBAV_CONFIG_H
111         ist->dec = s->codec;
112         ist->dec_ctx = avcodec_alloc_context3(ist->dec);
113         avcodec_copy_context(ist->dec_ctx, s);
114         ret = hw_device_setup_for_decode(ist);
115         s->hw_device_ctx = ist->dec_ctx->hw_device_ctx;
116         ALOGD_IF(DEBUG_HWACCEL, "hw_device_setup_for_decode: %d ctx=%p hw_device_ctx=%p pix_fmts=%d", ret, s, s->hw_device_ctx, *p);
117 #endif
118         break;
119     }
120
121     ALOGI("hw codec %s %sabled: s=%p ist=%p pix_fmts=%d", avcodec_get_name(s->codec_id), ret ? "dis" : "en", s, ist, *p);
122     return *p;
123 }
124
125 static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
126 {
127     InputStream *ist = s->opaque;
128     ALOGV_IF(DEBUG_HWACCEL, "get_buffer: s=%p ist=%p format=%d hwaccel_pix_fmt=%d",
129             s, ist, frame->format, ist->hwaccel_pix_fmt);
130
131     if (ist->hwaccel_get_buffer && frame->format == ist->hwaccel_pix_fmt)
132         return ist->hwaccel_get_buffer(s, frame, flags);
133
134     return avcodec_default_get_buffer2(s, frame, flags);
135 }
136
137 /* END: Extracted from ffmpeg.c */
138
139 int ffmpeg_hwaccel_init(AVCodecContext *avctx)
140 {
141     if (!property_get_bool("media.sf.hwaccel", 0))
142         return 0;
143
144     InputStream *ist = av_mallocz(sizeof(*ist));
145     if (!ist)
146         return AVERROR(ENOMEM);
147
148     ist->hwaccel_id = HWACCEL_AUTO;
149     ist->hwaccel_device = "android";
150     ist->hwaccel_output_format = AV_PIX_FMT_YUV420P;
151
152     avctx->opaque = ist;
153     avctx->get_format = get_format;
154     avctx->get_buffer2 = get_buffer;
155     avctx->thread_safe_callbacks = 1;
156     av_opt_set_int(avctx, "refcounted_frames", 1, 0);
157
158     ALOGD_IF(DEBUG_HWACCEL, "ffmpeg_hwaccel_init ctx=%p ist=%p", avctx, ist);
159     return 0;
160 }
161
162 void ffmpeg_hwaccel_deinit(AVCodecContext *avctx)
163 {
164     if (avctx->opaque) {
165         InputStream *ist = avctx->opaque;
166         if (ist->hwaccel_uninit)
167             ist->hwaccel_uninit(avctx);
168 #ifdef LIBAV_CONFIG_H
169         avcodec_free_context(&ist->dec_ctx);
170 #endif
171         av_freep(&avctx->opaque);
172     }
173 }