Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * Copyright (c) 2012 Derek Buitenhuis
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public
8
 * License as published by the Free Software Foundation;
9
 * version 2 of the License.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
 
21
/**
22
 * @file
23
 * Known FOURCCs:
24
 *     'ULY0' (YCbCr 4:2:0), 'ULY2' (YCbCr 4:2:2), 'ULRG' (RGB), 'ULRA' (RGBA),
25
 *     'ULH0' (YCbCr 4:2:0 BT.709), 'ULH2' (YCbCr 4:2:2 BT.709)
26
 */
27
 
28
extern "C" {
29
#include "libavutil/avassert.h"
30
#include "avcodec.h"
31
#include "internal.h"
32
}
33
 
34
#include "libutvideo.h"
35
#include "put_bits.h"
36
 
37
static av_cold int utvideo_encode_init(AVCodecContext *avctx)
38
{
39
    UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
40
    UtVideoExtra *info;
41
    uint32_t flags, in_format;
42
 
43
    switch (avctx->pix_fmt) {
44
    case AV_PIX_FMT_YUV420P:
45
        in_format = UTVF_YV12;
46
        avctx->bits_per_coded_sample = 12;
47
        avctx->codec_tag = MKTAG('U', 'L', 'Y', '0');
48
        break;
49
    case AV_PIX_FMT_YUYV422:
50
        in_format = UTVF_YUYV;
51
        avctx->bits_per_coded_sample = 16;
52
        avctx->codec_tag = MKTAG('U', 'L', 'Y', '2');
53
        break;
54
    case AV_PIX_FMT_BGR24:
55
        in_format = UTVF_NFCC_BGR_BU;
56
        avctx->bits_per_coded_sample = 24;
57
        avctx->codec_tag = MKTAG('U', 'L', 'R', 'G');
58
        break;
59
    case AV_PIX_FMT_RGB32:
60
        in_format = UTVF_NFCC_BGRA_BU;
61
        avctx->bits_per_coded_sample = 32;
62
        avctx->codec_tag = MKTAG('U', 'L', 'R', 'A');
63
        break;
64
    default:
65
        return AVERROR(EINVAL);
66
    }
67
 
68
    /* Check before we alloc anything */
69
    if (avctx->prediction_method != 0 && avctx->prediction_method != 2) {
70
        av_log(avctx, AV_LOG_ERROR, "Invalid prediction method.\n");
71
        return AVERROR(EINVAL);
72
    }
73
 
74
    flags = ((avctx->prediction_method + 1) << 8) | (avctx->thread_count - 1);
75
 
76
    avctx->priv_data = utv;
77
    avctx->coded_frame = avcodec_alloc_frame();
78
 
79
    /* Alloc extradata buffer */
80
    info = (UtVideoExtra *)av_malloc(sizeof(*info));
81
 
82
    if (info == NULL) {
83
        av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata buffer.\n");
84
        return AVERROR(ENOMEM);
85
    }
86
 
87
    /*
88
     * We use this buffer to hold the data that Ut Video returns,
89
     * since we cannot decode planes separately with it.
90
     */
91
    utv->buf_size = avpicture_get_size(avctx->pix_fmt,
92
                                       avctx->width, avctx->height);
93
    utv->buffer = (uint8_t *)av_malloc(utv->buf_size);
94
 
95
    if (utv->buffer == NULL) {
96
        av_log(avctx, AV_LOG_ERROR, "Could not allocate output buffer.\n");
97
        return AVERROR(ENOMEM);
98
    }
99
 
100
    /*
101
     * Create a Ut Video instance. Since the function wants
102
     * an "interface name" string, pass it the name of the lib.
103
     */
104
    utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), "libavcodec");
105
 
106
    /* Initialize encoder */
107
    utv->codec->EncodeBegin(in_format, avctx->width, avctx->height,
108
                            CBGROSSWIDTH_WINDOWS);
109
 
110
    /* Get extradata from encoder */
111
    avctx->extradata_size = utv->codec->EncodeGetExtraDataSize();
112
    utv->codec->EncodeGetExtraData(info, avctx->extradata_size, in_format,
113
                                   avctx->width, avctx->height,
114
                                   CBGROSSWIDTH_WINDOWS);
115
    avctx->extradata = (uint8_t *)info;
116
 
117
    /* Set flags */
118
    utv->codec->SetState(&flags, sizeof(flags));
119
 
120
    return 0;
121
}
122
 
123
static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
124
                                const AVFrame *pic, int *got_packet)
125
{
126
    UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
127
    int w = avctx->width, h = avctx->height;
128
    int ret, rgb_size, i;
129
    bool keyframe;
130
    uint8_t *y, *u, *v;
131
    uint8_t *dst;
132
 
133
    /* Alloc buffer */
134
    if ((ret = ff_alloc_packet2(avctx, pkt, utv->buf_size)) < 0)
135
        return ret;
136
 
137
    dst = pkt->data;
138
 
139
    /* Move input if needed data into Ut Video friendly buffer */
140
    switch (avctx->pix_fmt) {
141
    case AV_PIX_FMT_YUV420P:
142
        y = utv->buffer;
143
        u = y + w * h;
144
        v = u + w * h / 4;
145
        for (i = 0; i < h; i++) {
146
            memcpy(y, pic->data[0] + i * pic->linesize[0], w);
147
            y += w;
148
        }
149
        for (i = 0; i < h / 2; i++) {
150
            memcpy(u, pic->data[2] + i * pic->linesize[2], w >> 1);
151
            memcpy(v, pic->data[1] + i * pic->linesize[1], w >> 1);
152
            u += w >> 1;
153
            v += w >> 1;
154
        }
155
        break;
156
    case AV_PIX_FMT_YUYV422:
157
        for (i = 0; i < h; i++)
158
            memcpy(utv->buffer + i * (w << 1),
159
                   pic->data[0] + i * pic->linesize[0], w << 1);
160
        break;
161
    case AV_PIX_FMT_BGR24:
162
    case AV_PIX_FMT_RGB32:
163
        /* Ut Video takes bottom-up BGR */
164
        rgb_size = avctx->pix_fmt == AV_PIX_FMT_BGR24 ? 3 : 4;
165
        for (i = 0; i < h; i++)
166
            memcpy(utv->buffer + (h - i - 1) * w * rgb_size,
167
                   pic->data[0] + i * pic->linesize[0],
168
                   w * rgb_size);
169
        break;
170
    default:
171
        return AVERROR(EINVAL);
172
    }
173
 
174
    /* Encode frame */
175
    pkt->size = utv->codec->EncodeFrame(dst, &keyframe, utv->buffer);
176
 
177
    if (!pkt->size) {
178
        av_log(avctx, AV_LOG_ERROR, "EncodeFrame failed!\n");
179
        return AVERROR_INVALIDDATA;
180
    }
181
 
182
    /*
183
     * Ut Video is intra-only and every frame is a keyframe,
184
     * and the API always returns true. In case something
185
     * durastic changes in the future, such as inter support,
186
     * assert that this is true.
187
     */
188
    av_assert2(keyframe == true);
189
    avctx->coded_frame->key_frame = 1;
190
    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
191
 
192
    pkt->flags |= AV_PKT_FLAG_KEY;
193
    *got_packet = 1;
194
    return 0;
195
}
196
 
197
static av_cold int utvideo_encode_close(AVCodecContext *avctx)
198
{
199
    UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
200
 
201
    av_freep(&avctx->coded_frame);
202
    av_freep(&avctx->extradata);
203
    av_freep(&utv->buffer);
204
 
205
    utv->codec->EncodeEnd();
206
    CCodec::DeleteInstance(utv->codec);
207
 
208
    return 0;
209
}
210
 
211
AVCodec ff_libutvideo_encoder = {
212
    "libutvideo",
213
    NULL_IF_CONFIG_SMALL("Ut Video"),
214
    AVMEDIA_TYPE_VIDEO,
215
    AV_CODEC_ID_UTVIDEO,
216
    CODEC_CAP_AUTO_THREADS | CODEC_CAP_LOSSLESS,
217
    NULL, /* supported_framerates */
218
    (const enum AVPixelFormat[]) {
219
        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUYV422, AV_PIX_FMT_BGR24,
220
        AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
221
    },
222
    NULL, /* supported_samplerates */
223
    NULL, /* sample_fmts */
224
    NULL, /* channel_layouts */
225
    0,    /* max_lowres */
226
    NULL, /* priv_class */
227
    NULL, /* profiles */
228
    sizeof(UtVideoContext),
229
    NULL, /* next */
230
    NULL, /* init_thread_copy */
231
    NULL, /* update_thread_context */
232
    NULL, /* defaults */
233
    NULL, /* init_static_data */
234
    utvideo_encode_init,
235
    NULL, /* encode */
236
    utvideo_encode_frame,
237
    NULL, /* decode */
238
    utvideo_encode_close,
239
    NULL, /* flush */
240
};