Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * V210 encoder
  3.  *
  4.  * Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at>
  5.  * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
  6.  *
  7.  * This file is part of FFmpeg.
  8.  *
  9.  * FFmpeg is free software; you can redistribute it and/or
  10.  * modify it under the terms of the GNU Lesser General Public
  11.  * License as published by the Free Software Foundation; either
  12.  * version 2.1 of the License, or (at your option) any later version.
  13.  *
  14.  * FFmpeg is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17.  * Lesser General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU Lesser General Public
  20.  * License along with FFmpeg; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22.  */
  23.  
  24. #include "avcodec.h"
  25. #include "bytestream.h"
  26. #include "internal.h"
  27. #include "v210enc.h"
  28.  
  29. #define CLIP(v) av_clip(v, 4, 1019)
  30. #define CLIP8(v) av_clip(v, 1, 254)
  31.  
  32. #define WRITE_PIXELS(a, b, c)           \
  33.     do {                                \
  34.         val  =  CLIP(*a++);             \
  35.         val |= (CLIP(*b++) << 10) |     \
  36.                (CLIP(*c++) << 20);      \
  37.         AV_WL32(dst, val);              \
  38.         dst += 4;                       \
  39.     } while (0)
  40.  
  41. #define WRITE_PIXELS8(a, b, c)          \
  42.     do {                                \
  43.         val  = (CLIP8(*a++) << 2);      \
  44.         val |= (CLIP8(*b++) << 12) |    \
  45.                (CLIP8(*c++) << 22);     \
  46.         AV_WL32(dst, val);              \
  47.         dst += 4;                       \
  48.     } while (0)
  49.  
  50. static void v210_planar_pack_8_c(const uint8_t *y, const uint8_t *u,
  51.                                  const uint8_t *v, uint8_t *dst,
  52.                                  ptrdiff_t width)
  53. {
  54.     uint32_t val;
  55.     int i;
  56.  
  57.     /* unroll this to match the assembly */
  58.     for (i = 0; i < width - 11; i += 12) {
  59.         WRITE_PIXELS8(u, y, v);
  60.         WRITE_PIXELS8(y, u, y);
  61.         WRITE_PIXELS8(v, y, u);
  62.         WRITE_PIXELS8(y, v, y);
  63.         WRITE_PIXELS8(u, y, v);
  64.         WRITE_PIXELS8(y, u, y);
  65.         WRITE_PIXELS8(v, y, u);
  66.         WRITE_PIXELS8(y, v, y);
  67.     }
  68. }
  69.  
  70. static void v210_planar_pack_10_c(const uint16_t *y, const uint16_t *u,
  71.                                   const uint16_t *v, uint8_t *dst,
  72.                                   ptrdiff_t width)
  73. {
  74.     uint32_t val;
  75.     int i;
  76.  
  77.     for (i = 0; i < width - 5; i += 6) {
  78.         WRITE_PIXELS(u, y, v);
  79.         WRITE_PIXELS(y, u, y);
  80.         WRITE_PIXELS(v, y, u);
  81.         WRITE_PIXELS(y, v, y);
  82.     }
  83. }
  84.  
  85. static av_cold int encode_init(AVCodecContext *avctx)
  86. {
  87.     V210EncContext *s = avctx->priv_data;
  88.  
  89.     if (avctx->width & 1) {
  90.         av_log(avctx, AV_LOG_ERROR, "v210 needs even width\n");
  91.         return AVERROR(EINVAL);
  92.     }
  93.  
  94. #if FF_API_CODED_FRAME
  95. FF_DISABLE_DEPRECATION_WARNINGS
  96.     avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
  97. FF_ENABLE_DEPRECATION_WARNINGS
  98. #endif
  99.  
  100.     s->pack_line_8  = v210_planar_pack_8_c;
  101.     s->pack_line_10 = v210_planar_pack_10_c;
  102.  
  103.     if (ARCH_X86)
  104.         ff_v210enc_init_x86(s);
  105.  
  106.     return 0;
  107. }
  108.  
  109. static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
  110.                         const AVFrame *pic, int *got_packet)
  111. {
  112.     V210EncContext *s = avctx->priv_data;
  113.     int aligned_width = ((avctx->width + 47) / 48) * 48;
  114.     int stride = aligned_width * 8 / 3;
  115.     int line_padding = stride - ((avctx->width * 8 + 11) / 12) * 4;
  116.     int h, w, ret;
  117.     uint8_t *dst;
  118.  
  119.     ret = ff_alloc_packet2(avctx, pkt, avctx->height * stride, avctx->height * stride);
  120.     if (ret < 0) {
  121.         av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
  122.         return ret;
  123.     }
  124.     dst = pkt->data;
  125.  
  126.     if (pic->format == AV_PIX_FMT_YUV422P10) {
  127.         const uint16_t *y = (const uint16_t *)pic->data[0];
  128.         const uint16_t *u = (const uint16_t *)pic->data[1];
  129.         const uint16_t *v = (const uint16_t *)pic->data[2];
  130.         for (h = 0; h < avctx->height; h++) {
  131.             uint32_t val;
  132.             w = (avctx->width / 6) * 6;
  133.             s->pack_line_10(y, u, v, dst, w);
  134.  
  135.             y += w;
  136.             u += w >> 1;
  137.             v += w >> 1;
  138.             dst += (w / 6) * 16;
  139.             if (w < avctx->width - 1) {
  140.                 WRITE_PIXELS(u, y, v);
  141.  
  142.                 val = CLIP(*y++);
  143.                 if (w == avctx->width - 2) {
  144.                     AV_WL32(dst, val);
  145.                     dst += 4;
  146.                 }
  147.             }
  148.             if (w < avctx->width - 3) {
  149.                 val |= (CLIP(*u++) << 10) | (CLIP(*y++) << 20);
  150.                 AV_WL32(dst, val);
  151.                 dst += 4;
  152.  
  153.                 val = CLIP(*v++) | (CLIP(*y++) << 10);
  154.                 AV_WL32(dst, val);
  155.                 dst += 4;
  156.             }
  157.  
  158.             memset(dst, 0, line_padding);
  159.             dst += line_padding;
  160.             y += pic->linesize[0] / 2 - avctx->width;
  161.             u += pic->linesize[1] / 2 - avctx->width / 2;
  162.             v += pic->linesize[2] / 2 - avctx->width / 2;
  163.         }
  164.     } else if(pic->format == AV_PIX_FMT_YUV422P) {
  165.         const uint8_t *y = pic->data[0];
  166.         const uint8_t *u = pic->data[1];
  167.         const uint8_t *v = pic->data[2];
  168.         for (h = 0; h < avctx->height; h++) {
  169.             uint32_t val;
  170.             w = (avctx->width / 12) * 12;
  171.             s->pack_line_8(y, u, v, dst, w);
  172.  
  173.             y += w;
  174.             u += w >> 1;
  175.             v += w >> 1;
  176.             dst += (w / 12) * 32;
  177.  
  178.             for (; w < avctx->width - 5; w += 6) {
  179.                 WRITE_PIXELS8(u, y, v);
  180.                 WRITE_PIXELS8(y, u, y);
  181.                 WRITE_PIXELS8(v, y, u);
  182.                 WRITE_PIXELS8(y, v, y);
  183.             }
  184.             if (w < avctx->width - 1) {
  185.                 WRITE_PIXELS8(u, y, v);
  186.  
  187.                 val = CLIP8(*y++) << 2;
  188.                 if (w == avctx->width - 2) {
  189.                     AV_WL32(dst, val);
  190.                     dst += 4;
  191.                 }
  192.             }
  193.             if (w < avctx->width - 3) {
  194.                 val |= (CLIP8(*u++) << 12) | (CLIP8(*y++) << 22);
  195.                 AV_WL32(dst, val);
  196.                 dst += 4;
  197.  
  198.                 val = (CLIP8(*v++) << 2) | (CLIP8(*y++) << 12);
  199.                 AV_WL32(dst, val);
  200.                 dst += 4;
  201.             }
  202.             memset(dst, 0, line_padding);
  203.             dst += line_padding;
  204.  
  205.             y += pic->linesize[0] - avctx->width;
  206.             u += pic->linesize[1] - avctx->width / 2;
  207.             v += pic->linesize[2] - avctx->width / 2;
  208.         }
  209.     }
  210.  
  211.     pkt->flags |= AV_PKT_FLAG_KEY;
  212.     *got_packet = 1;
  213.     return 0;
  214. }
  215.  
  216. AVCodec ff_v210_encoder = {
  217.     .name           = "v210",
  218.     .long_name      = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"),
  219.     .type           = AVMEDIA_TYPE_VIDEO,
  220.     .id             = AV_CODEC_ID_V210,
  221.     .priv_data_size = sizeof(V210EncContext),
  222.     .init           = encode_init,
  223.     .encode2        = encode_frame,
  224.     .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE },
  225. };
  226.