1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * bitpacked encoder
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (c) 2021 Limin Wang
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include "avcodec.h"
24cabdff1aSopenharmony_ci#include "codec_internal.h"
25cabdff1aSopenharmony_ci#include "encode.h"
26cabdff1aSopenharmony_ci#include "internal.h"
27cabdff1aSopenharmony_ci#include "put_bits.h"
28cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h"
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_cistruct BitpackedContext {
31cabdff1aSopenharmony_ci    int (*encode)(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame);
32cabdff1aSopenharmony_ci};
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_cistatic int encode_yuv422p10(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame)
35cabdff1aSopenharmony_ci{
36cabdff1aSopenharmony_ci    const int buf_size = avctx->height * avctx->width * avctx->bits_per_coded_sample / 8;
37cabdff1aSopenharmony_ci    int ret;
38cabdff1aSopenharmony_ci    uint8_t *dst;
39cabdff1aSopenharmony_ci    const uint16_t *y;
40cabdff1aSopenharmony_ci    const uint16_t *u;
41cabdff1aSopenharmony_ci    const uint16_t *v;
42cabdff1aSopenharmony_ci    PutBitContext pb;
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_ci    ret = ff_get_encode_buffer(avctx, pkt,  buf_size, 0);
45cabdff1aSopenharmony_ci    if (ret < 0) {
46cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
47cabdff1aSopenharmony_ci        return ret;
48cabdff1aSopenharmony_ci    }
49cabdff1aSopenharmony_ci    dst = pkt->data;
50cabdff1aSopenharmony_ci
51cabdff1aSopenharmony_ci    init_put_bits(&pb, dst, buf_size);
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci    for (int i = 0; i < avctx->height; i++) {
54cabdff1aSopenharmony_ci        y = (uint16_t*)(frame->data[0] + i * frame->linesize[0]);
55cabdff1aSopenharmony_ci        u = (uint16_t*)(frame->data[1] + i * frame->linesize[1]);
56cabdff1aSopenharmony_ci        v = (uint16_t*)(frame->data[2] + i * frame->linesize[2]);
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci        for (int j = 0; j < avctx->width; j += 2) {
59cabdff1aSopenharmony_ci            /* u, y0, v, y1 */
60cabdff1aSopenharmony_ci            put_bits(&pb, 10, av_clip_uintp2(*u++, 10));
61cabdff1aSopenharmony_ci            put_bits(&pb, 10, av_clip_uintp2(*y++, 10));
62cabdff1aSopenharmony_ci            put_bits(&pb, 10, av_clip_uintp2(*v++, 10));
63cabdff1aSopenharmony_ci            put_bits(&pb, 10, av_clip_uintp2(*y++, 10));
64cabdff1aSopenharmony_ci        }
65cabdff1aSopenharmony_ci    }
66cabdff1aSopenharmony_ci    flush_put_bits(&pb);
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci    return 0;
69cabdff1aSopenharmony_ci}
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_cistatic av_cold int encode_init(AVCodecContext *avctx)
73cabdff1aSopenharmony_ci{
74cabdff1aSopenharmony_ci    struct BitpackedContext *s = avctx->priv_data;
75cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci    if (avctx->width & 1) {
78cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "bitpacked needs even width\n");
79cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
80cabdff1aSopenharmony_ci    }
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci    avctx->bits_per_coded_sample = av_get_bits_per_pixel(desc);
83cabdff1aSopenharmony_ci    avctx->bit_rate = ff_guess_coded_bitrate(avctx);
84cabdff1aSopenharmony_ci
85cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_YUV422P10)
86cabdff1aSopenharmony_ci        s->encode = encode_yuv422p10;
87cabdff1aSopenharmony_ci    else
88cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci    return 0;
91cabdff1aSopenharmony_ci}
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_cistatic int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
94cabdff1aSopenharmony_ci                        const AVFrame *frame, int *got_packet)
95cabdff1aSopenharmony_ci{
96cabdff1aSopenharmony_ci    struct BitpackedContext *s = avctx->priv_data;
97cabdff1aSopenharmony_ci    int ret;
98cabdff1aSopenharmony_ci
99cabdff1aSopenharmony_ci    ret = s->encode(avctx, pkt, frame);
100cabdff1aSopenharmony_ci    if (ret)
101cabdff1aSopenharmony_ci        return ret;
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_ci    *got_packet = 1;
104cabdff1aSopenharmony_ci    return 0;
105cabdff1aSopenharmony_ci}
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_ciconst FFCodec ff_bitpacked_encoder = {
108cabdff1aSopenharmony_ci    .p.name         = "bitpacked",
109cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Bitpacked"),
110cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
111cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_BITPACKED,
112cabdff1aSopenharmony_ci    .priv_data_size = sizeof(struct BitpackedContext),
113cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
114cabdff1aSopenharmony_ci    .init           = encode_init,
115cabdff1aSopenharmony_ci    FF_CODEC_ENCODE_CB(encode_frame),
116cabdff1aSopenharmony_ci    .p.pix_fmts     = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P10,
117cabdff1aSopenharmony_ci                                                    AV_PIX_FMT_NONE },
118cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
119cabdff1aSopenharmony_ci};
120