1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * DPX (.dpx) image encoder 3cabdff1aSopenharmony_ci * Copyright (c) 2011 Peter Ross <pross@xvid.org> 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/common.h" 23cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 24cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 25cabdff1aSopenharmony_ci#include "avcodec.h" 26cabdff1aSopenharmony_ci#include "codec_internal.h" 27cabdff1aSopenharmony_ci#include "encode.h" 28cabdff1aSopenharmony_ci#include "version.h" 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_citypedef struct DPXContext { 31cabdff1aSopenharmony_ci int big_endian; 32cabdff1aSopenharmony_ci int bits_per_component; 33cabdff1aSopenharmony_ci int num_components; 34cabdff1aSopenharmony_ci int descriptor; 35cabdff1aSopenharmony_ci int planar; 36cabdff1aSopenharmony_ci} DPXContext; 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_cistatic av_cold int encode_init(AVCodecContext *avctx) 39cabdff1aSopenharmony_ci{ 40cabdff1aSopenharmony_ci DPXContext *s = avctx->priv_data; 41cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci s->big_endian = !!(desc->flags & AV_PIX_FMT_FLAG_BE); 44cabdff1aSopenharmony_ci s->bits_per_component = desc->comp[0].depth; 45cabdff1aSopenharmony_ci s->num_components = desc->nb_components; 46cabdff1aSopenharmony_ci s->descriptor = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? 51 : 50; 47cabdff1aSopenharmony_ci s->planar = !!(desc->flags & AV_PIX_FMT_FLAG_PLANAR); 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_ci switch (avctx->pix_fmt) { 50cabdff1aSopenharmony_ci case AV_PIX_FMT_ABGR: 51cabdff1aSopenharmony_ci s->descriptor = 52; 52cabdff1aSopenharmony_ci break; 53cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY16BE: 54cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY16LE: 55cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY8: 56cabdff1aSopenharmony_ci s->descriptor = 6; 57cabdff1aSopenharmony_ci break; 58cabdff1aSopenharmony_ci case AV_PIX_FMT_GBRP10BE: 59cabdff1aSopenharmony_ci case AV_PIX_FMT_GBRP10LE: 60cabdff1aSopenharmony_ci case AV_PIX_FMT_GBRP12BE: 61cabdff1aSopenharmony_ci case AV_PIX_FMT_GBRP12LE: 62cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB24: 63cabdff1aSopenharmony_ci case AV_PIX_FMT_RGBA64BE: 64cabdff1aSopenharmony_ci case AV_PIX_FMT_RGBA64LE: 65cabdff1aSopenharmony_ci case AV_PIX_FMT_RGBA: 66cabdff1aSopenharmony_ci break; 67cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB48LE: 68cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB48BE: 69cabdff1aSopenharmony_ci if (avctx->bits_per_raw_sample) 70cabdff1aSopenharmony_ci s->bits_per_component = avctx->bits_per_raw_sample; 71cabdff1aSopenharmony_ci break; 72cabdff1aSopenharmony_ci } 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_ci return 0; 75cabdff1aSopenharmony_ci} 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_cistatic av_always_inline void write16_internal(int big_endian, void *p, int value) 78cabdff1aSopenharmony_ci{ 79cabdff1aSopenharmony_ci if (big_endian) AV_WB16(p, value); 80cabdff1aSopenharmony_ci else AV_WL16(p, value); 81cabdff1aSopenharmony_ci} 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_cistatic av_always_inline void write32_internal(int big_endian, void *p, int value) 84cabdff1aSopenharmony_ci{ 85cabdff1aSopenharmony_ci if (big_endian) AV_WB32(p, value); 86cabdff1aSopenharmony_ci else AV_WL32(p, value); 87cabdff1aSopenharmony_ci} 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci#define write16(p, value) write16_internal(s->big_endian, p, value) 90cabdff1aSopenharmony_ci#define write32(p, value) write32_internal(s->big_endian, p, value) 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_cistatic void encode_rgb48_10bit(AVCodecContext *avctx, const AVFrame *pic, 93cabdff1aSopenharmony_ci uint8_t *dst) 94cabdff1aSopenharmony_ci{ 95cabdff1aSopenharmony_ci DPXContext *s = avctx->priv_data; 96cabdff1aSopenharmony_ci const uint8_t *src = pic->data[0]; 97cabdff1aSopenharmony_ci int x, y; 98cabdff1aSopenharmony_ci 99cabdff1aSopenharmony_ci for (y = 0; y < avctx->height; y++) { 100cabdff1aSopenharmony_ci for (x = 0; x < avctx->width; x++) { 101cabdff1aSopenharmony_ci int value; 102cabdff1aSopenharmony_ci if (s->big_endian) { 103cabdff1aSopenharmony_ci value = ((AV_RB16(src + 6*x + 4) & 0xFFC0U) >> 4) 104cabdff1aSopenharmony_ci | ((AV_RB16(src + 6*x + 2) & 0xFFC0U) << 6) 105cabdff1aSopenharmony_ci | ((AV_RB16(src + 6*x + 0) & 0xFFC0U) << 16); 106cabdff1aSopenharmony_ci } else { 107cabdff1aSopenharmony_ci value = ((AV_RL16(src + 6*x + 4) & 0xFFC0U) >> 4) 108cabdff1aSopenharmony_ci | ((AV_RL16(src + 6*x + 2) & 0xFFC0U) << 6) 109cabdff1aSopenharmony_ci | ((AV_RL16(src + 6*x + 0) & 0xFFC0U) << 16); 110cabdff1aSopenharmony_ci } 111cabdff1aSopenharmony_ci write32(dst, value); 112cabdff1aSopenharmony_ci dst += 4; 113cabdff1aSopenharmony_ci } 114cabdff1aSopenharmony_ci src += pic->linesize[0]; 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci} 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_cistatic void encode_gbrp10(AVCodecContext *avctx, const AVFrame *pic, uint8_t *dst) 119cabdff1aSopenharmony_ci{ 120cabdff1aSopenharmony_ci DPXContext *s = avctx->priv_data; 121cabdff1aSopenharmony_ci const uint8_t *src[3] = {pic->data[0], pic->data[1], pic->data[2]}; 122cabdff1aSopenharmony_ci int x, y, i; 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci for (y = 0; y < avctx->height; y++) { 125cabdff1aSopenharmony_ci for (x = 0; x < avctx->width; x++) { 126cabdff1aSopenharmony_ci int value; 127cabdff1aSopenharmony_ci if (s->big_endian) { 128cabdff1aSopenharmony_ci value = (AV_RB16(src[0] + 2*x) << 12) 129cabdff1aSopenharmony_ci | (AV_RB16(src[1] + 2*x) << 2) 130cabdff1aSopenharmony_ci | ((unsigned)AV_RB16(src[2] + 2*x) << 22); 131cabdff1aSopenharmony_ci } else { 132cabdff1aSopenharmony_ci value = (AV_RL16(src[0] + 2*x) << 12) 133cabdff1aSopenharmony_ci | (AV_RL16(src[1] + 2*x) << 2) 134cabdff1aSopenharmony_ci | ((unsigned)AV_RL16(src[2] + 2*x) << 22); 135cabdff1aSopenharmony_ci } 136cabdff1aSopenharmony_ci write32(dst, value); 137cabdff1aSopenharmony_ci dst += 4; 138cabdff1aSopenharmony_ci } 139cabdff1aSopenharmony_ci for (i = 0; i < 3; i++) 140cabdff1aSopenharmony_ci src[i] += pic->linesize[i]; 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci} 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_cistatic void encode_gbrp12(AVCodecContext *avctx, const AVFrame *pic, uint8_t *dst) 145cabdff1aSopenharmony_ci{ 146cabdff1aSopenharmony_ci DPXContext *s = avctx->priv_data; 147cabdff1aSopenharmony_ci const uint16_t *src[3] = {(uint16_t*)pic->data[0], 148cabdff1aSopenharmony_ci (uint16_t*)pic->data[1], 149cabdff1aSopenharmony_ci (uint16_t*)pic->data[2]}; 150cabdff1aSopenharmony_ci int x, y, i, pad; 151cabdff1aSopenharmony_ci pad = avctx->width*6; 152cabdff1aSopenharmony_ci pad = (FFALIGN(pad, 4) - pad) >> 1; 153cabdff1aSopenharmony_ci for (y = 0; y < avctx->height; y++) { 154cabdff1aSopenharmony_ci for (x = 0; x < avctx->width; x++) { 155cabdff1aSopenharmony_ci uint16_t value[3]; 156cabdff1aSopenharmony_ci if (s->big_endian) { 157cabdff1aSopenharmony_ci value[1] = AV_RB16(src[0] + x) << 4; 158cabdff1aSopenharmony_ci value[2] = AV_RB16(src[1] + x) << 4; 159cabdff1aSopenharmony_ci value[0] = AV_RB16(src[2] + x) << 4; 160cabdff1aSopenharmony_ci } else { 161cabdff1aSopenharmony_ci value[1] = AV_RL16(src[0] + x) << 4; 162cabdff1aSopenharmony_ci value[2] = AV_RL16(src[1] + x) << 4; 163cabdff1aSopenharmony_ci value[0] = AV_RL16(src[2] + x) << 4; 164cabdff1aSopenharmony_ci } 165cabdff1aSopenharmony_ci for (i = 0; i < 3; i++, dst += 2) 166cabdff1aSopenharmony_ci write16(dst, value[i]); 167cabdff1aSopenharmony_ci } 168cabdff1aSopenharmony_ci for (i = 0; i < pad; i++, dst += 2) 169cabdff1aSopenharmony_ci AV_WN16(dst, 0); 170cabdff1aSopenharmony_ci for (i = 0; i < 3; i++) 171cabdff1aSopenharmony_ci src[i] += pic->linesize[i]/2; 172cabdff1aSopenharmony_ci } 173cabdff1aSopenharmony_ci} 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_cistatic int encode_frame(AVCodecContext *avctx, AVPacket *pkt, 176cabdff1aSopenharmony_ci const AVFrame *frame, int *got_packet) 177cabdff1aSopenharmony_ci{ 178cabdff1aSopenharmony_ci DPXContext *s = avctx->priv_data; 179cabdff1aSopenharmony_ci int size, ret, need_align, len; 180cabdff1aSopenharmony_ci uint8_t *buf; 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci#define HEADER_SIZE 1664 /* DPX Generic header */ 183cabdff1aSopenharmony_ci if (s->bits_per_component == 10) 184cabdff1aSopenharmony_ci size = avctx->height * avctx->width * 4; 185cabdff1aSopenharmony_ci else if (s->bits_per_component == 12) { 186cabdff1aSopenharmony_ci // 3 components, 12 bits put on 16 bits 187cabdff1aSopenharmony_ci len = avctx->width*6; 188cabdff1aSopenharmony_ci size = FFALIGN(len, 4); 189cabdff1aSopenharmony_ci need_align = size - len; 190cabdff1aSopenharmony_ci size *= avctx->height; 191cabdff1aSopenharmony_ci } else { 192cabdff1aSopenharmony_ci // N components, M bits 193cabdff1aSopenharmony_ci len = avctx->width * s->num_components * s->bits_per_component >> 3; 194cabdff1aSopenharmony_ci size = FFALIGN(len, 4); 195cabdff1aSopenharmony_ci need_align = size - len; 196cabdff1aSopenharmony_ci size *= avctx->height; 197cabdff1aSopenharmony_ci } 198cabdff1aSopenharmony_ci if ((ret = ff_get_encode_buffer(avctx, pkt, size + HEADER_SIZE, 0)) < 0) 199cabdff1aSopenharmony_ci return ret; 200cabdff1aSopenharmony_ci buf = pkt->data; 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci memset(buf, 0, HEADER_SIZE); 203cabdff1aSopenharmony_ci 204cabdff1aSopenharmony_ci /* File information header */ 205cabdff1aSopenharmony_ci write32(buf, MKBETAG('S','D','P','X')); 206cabdff1aSopenharmony_ci write32(buf + 4, HEADER_SIZE); 207cabdff1aSopenharmony_ci memcpy (buf + 8, "V1.0", 4); 208cabdff1aSopenharmony_ci write32(buf + 20, 1); /* new image */ 209cabdff1aSopenharmony_ci write32(buf + 24, HEADER_SIZE); 210cabdff1aSopenharmony_ci if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) 211cabdff1aSopenharmony_ci memcpy (buf + 160, LIBAVCODEC_IDENT, FFMIN(sizeof(LIBAVCODEC_IDENT), 100)); 212cabdff1aSopenharmony_ci write32(buf + 660, 0xFFFFFFFF); /* unencrypted */ 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_ci /* Image information header */ 215cabdff1aSopenharmony_ci write16(buf + 768, 0); /* orientation; left to right, top to bottom */ 216cabdff1aSopenharmony_ci write16(buf + 770, 1); /* number of elements */ 217cabdff1aSopenharmony_ci write32(buf + 772, avctx->width); 218cabdff1aSopenharmony_ci write32(buf + 776, avctx->height); 219cabdff1aSopenharmony_ci buf[800] = s->descriptor; 220cabdff1aSopenharmony_ci buf[801] = 2; /* linear transfer */ 221cabdff1aSopenharmony_ci buf[802] = 2; /* linear colorimetric */ 222cabdff1aSopenharmony_ci buf[803] = s->bits_per_component; 223cabdff1aSopenharmony_ci write16(buf + 804, (s->bits_per_component == 10 || s->bits_per_component == 12) ? 224cabdff1aSopenharmony_ci 1 : 0); /* packing method */ 225cabdff1aSopenharmony_ci write32(buf + 808, HEADER_SIZE); /* data offset */ 226cabdff1aSopenharmony_ci 227cabdff1aSopenharmony_ci /* Image source information header */ 228cabdff1aSopenharmony_ci write32(buf + 1628, avctx->sample_aspect_ratio.num); 229cabdff1aSopenharmony_ci write32(buf + 1632, avctx->sample_aspect_ratio.den); 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci switch(s->bits_per_component) { 232cabdff1aSopenharmony_ci case 8: 233cabdff1aSopenharmony_ci case 16: 234cabdff1aSopenharmony_ci if (need_align) { 235cabdff1aSopenharmony_ci int j; 236cabdff1aSopenharmony_ci const uint8_t *src = frame->data[0]; 237cabdff1aSopenharmony_ci uint8_t *dst = pkt->data + HEADER_SIZE; 238cabdff1aSopenharmony_ci size = (len + need_align) * avctx->height; 239cabdff1aSopenharmony_ci for (j=0; j<avctx->height; j++) { 240cabdff1aSopenharmony_ci memcpy(dst, src, len); 241cabdff1aSopenharmony_ci memset(dst + len, 0, need_align); 242cabdff1aSopenharmony_ci dst += len + need_align; 243cabdff1aSopenharmony_ci src += frame->linesize[0]; 244cabdff1aSopenharmony_ci } 245cabdff1aSopenharmony_ci } else { 246cabdff1aSopenharmony_ci size = av_image_copy_to_buffer(buf + HEADER_SIZE, pkt->size - HEADER_SIZE, 247cabdff1aSopenharmony_ci (const uint8_t**)frame->data, frame->linesize, 248cabdff1aSopenharmony_ci avctx->pix_fmt, 249cabdff1aSopenharmony_ci avctx->width, avctx->height, 1); 250cabdff1aSopenharmony_ci } 251cabdff1aSopenharmony_ci if (size < 0) 252cabdff1aSopenharmony_ci return size; 253cabdff1aSopenharmony_ci break; 254cabdff1aSopenharmony_ci case 10: 255cabdff1aSopenharmony_ci if (s->planar) 256cabdff1aSopenharmony_ci encode_gbrp10(avctx, frame, buf + HEADER_SIZE); 257cabdff1aSopenharmony_ci else 258cabdff1aSopenharmony_ci encode_rgb48_10bit(avctx, frame, buf + HEADER_SIZE); 259cabdff1aSopenharmony_ci break; 260cabdff1aSopenharmony_ci case 12: 261cabdff1aSopenharmony_ci encode_gbrp12(avctx, frame, buf + HEADER_SIZE); 262cabdff1aSopenharmony_ci break; 263cabdff1aSopenharmony_ci default: 264cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth: %d\n", s->bits_per_component); 265cabdff1aSopenharmony_ci return -1; 266cabdff1aSopenharmony_ci } 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_ci size += HEADER_SIZE; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci write32(buf + 16, size); /* file size */ 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci *got_packet = 1; 273cabdff1aSopenharmony_ci 274cabdff1aSopenharmony_ci return 0; 275cabdff1aSopenharmony_ci} 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_ciconst FFCodec ff_dpx_encoder = { 278cabdff1aSopenharmony_ci .p.name = "dpx", 279cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("DPX (Digital Picture Exchange) image"), 280cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 281cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_DPX, 282cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 283cabdff1aSopenharmony_ci .priv_data_size = sizeof(DPXContext), 284cabdff1aSopenharmony_ci .init = encode_init, 285cabdff1aSopenharmony_ci FF_CODEC_ENCODE_CB(encode_frame), 286cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]){ 287cabdff1aSopenharmony_ci AV_PIX_FMT_GRAY8, 288cabdff1aSopenharmony_ci AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, 289cabdff1aSopenharmony_ci AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, 290cabdff1aSopenharmony_ci AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE, 291cabdff1aSopenharmony_ci AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE, 292cabdff1aSopenharmony_ci AV_PIX_FMT_GBRP10LE, AV_PIX_FMT_GBRP10BE, 293cabdff1aSopenharmony_ci AV_PIX_FMT_GBRP12LE, AV_PIX_FMT_GBRP12BE, 294cabdff1aSopenharmony_ci AV_PIX_FMT_NONE}, 295cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 296cabdff1aSopenharmony_ci}; 297