1 /*
2 * Vidvox Hap encoder
3 * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
4 * Copyright (C) 2015 Tom Butterworth <bangnoise@gmail.com>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /**
24 * @file
25 * Hap encoder
26 *
27 * Fourcc: Hap1, Hap5, HapY
28 *
29 * https://github.com/Vidvox/hap/blob/master/documentation/HapVideoDRAFT.md
30 */
31
32 #include <stdint.h>
33 #include "snappy-c.h"
34
39
45
46 #define HAP_MAX_CHUNKS 64
47
49 /* Short header: four bytes with a 24 bit size value */
51 /* Long header: eight bytes with a 32 bit size value */
53 };
54
56 {
58 int i, j;
59
62
63 for (j = 0; j < avctx->
height; j += 4) {
64 for (i = 0; i < avctx->
width; i += 4) {
67 out += step;
68 }
69 }
70
71 return 0;
72 }
73
74 /* section_length does not include the header */
77 int section_length,
79 {
80 /* The first three bytes are the length of the section (not including the
81 * header) or zero if using an eight-byte header.
82 * For an eight-byte header, the length is in the last four bytes.
83 * The fourth byte stores the section type. */
84 bytestream2_put_le24(pbc, header_length ==
HAP_HDR_LONG ? 0 : section_length);
85 bytestream2_put_byte(pbc, section_type);
86
88 bytestream2_put_le32(pbc, section_length);
89 }
90 }
91
93 {
95 int i, final_size = 0;
96
100 int ret;
101
102 if (i == 0) {
104 } else {
107 }
113
114 /* Compress with snappy too, write directly on packet buffer. */
117 if (ret != SNAPPY_OK) {
120 }
121
122 /* If there is no gain from snappy, just use the raw texture. */
130 } else {
132 }
133
135 }
136
137 return final_size;
138 }
139
141 {
142 /* Second-Stage Compressor Table (one byte per entry)
143 * + Chunk Size Table (four bytes per entry)
144 * + headers for both sections (short versions)
145 * = chunk_count + (4 * chunk_count) + 4 + 4 */
147 }
148
150 {
151 /* Top section header (long version) */
153
155 /* Decode Instructions header (short) + Decode Instructions Container */
157 }
158
160 }
161
163 {
165 int i;
166
169 /* Write a simple header */
172 } else {
173 /* Write a complex header with Decode Instructions Container */
180
183 }
184
187
190 }
191 }
192 }
193
196 {
199 int final_data_size, ret;
201
202 /* Allocate maximum size packet, shrink later. */
204 if (ret < 0)
205 return ret;
206
208 /* DXTC compression directly to the packet buffer. */
210 if (ret < 0)
211 return ret;
212
215 } else {
216 /* DXTC compression. */
218 if (ret < 0)
219 return ret;
220
221 /* Compress (using Snappy) the frame */
223 if (final_data_size < 0)
224 return final_data_size;
225 }
226
227 /* Write header at the start. */
229
232 *got_packet = 1;
233 return 0;
234 }
235
237 {
239 int ratio;
240 int corrected_chunk_count;
242
243 if (ret < 0) {
246 return ret;
247 }
248
253 }
254
256
259 ratio = 8;
263 break;
265 ratio = 4;
269 break;
271 ratio = 4;
275 break;
276 default:
279 }
280
281 /* Texture compression ratio is constant, so can we computer
282 * beforehand the final size of the uncompressed buffer. */
285
288 /* No benefit chunking uncompressed data */
289 corrected_chunk_count = 1;
290
293 break;
295 /* Round the chunk count to divide evenly on DXT block edges */
297 while ((ctx->
tex_size / (64 / ratio)) % corrected_chunk_count != 0) {
298 corrected_chunk_count--;
299 }
300
301 ctx->
max_snappy = snappy_max_compressed_length(ctx->
tex_size / corrected_chunk_count);
305 }
306 break;
307 default:
310 }
314 }
316 if (ret != 0)
317 return ret;
318
319 return 0;
320 }
321
323 {
325
327
328 return 0;
329 }
330
331 #define OFFSET(x) offsetof(HapContext, x)
332 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
343 };
344
350 };
351
358 .priv_class = &hapenc_class,
364 },
367 };
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
This structure describes decoded (raw) audio or video data.
int(* dxt1_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
#define LIBAVUTIL_VERSION_INT
void av_shrink_packet(AVPacket *pkt, int size)
Reduce packet size, correctly zeroing padding.
static av_cold int init(AVCodecContext *avctx)
int(* tex_fun)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Texture block (4x4) module.
static av_always_inline void bytestream2_init_writer(PutByteContext *p, uint8_t *buf, int buf_size)
const char * av_default_item_name(void *ptr)
Return the context name.
static av_cold int hap_init(AVCodecContext *avctx)
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int64_t min_size)
Check AVPacket size and/or allocate data.
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
static void hap_write_section_header(PutByteContext *pbc, enum HapHeaderLength header_length, int section_length, enum HapSectionType section_type)
static int compress_texture(AVCodecContext *avctx, uint8_t *out, int out_length, const AVFrame *f)
static const AVClass hapenc_class
int ff_hap_set_chunk_count(HapContext *ctx, int count, int first_in_frame)
#define AV_LOG_VERBOSE
Detailed information.
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
const char * name
Name of the codec implementation.
static av_cold int hap_close(AVCodecContext *avctx)
int(* dxt5_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
int flags
A combination of AV_PKT_FLAG values.
reference-counted frame API
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
static void hap_write_frame_header(HapContext *ctx, uint8_t *dst, int frame_length)
int width
picture width / height.
static const AVOption options[]
#define AV_LOG_INFO
Standard information.
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
av_cold void ff_hap_free_context(HapContext *ctx)
main external API structure.
unsigned int codec_tag
fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A').
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Describe the class of an AVClass context structure.
enum HapTextureFormat opt_tex_fmt
void ff_texturedspenc_init(TextureDSPContext *c)
static enum AVPixelFormat pix_fmts[]
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
static int hap_encode(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet)
common internal api header.
static int hap_decode_instructions_length(HapContext *ctx)
static int hap_compress_frame(AVCodecContext *avctx, uint8_t *dst)
enum HapCompressor compressor
#define MKTAG(a, b, c, d)
AVPixelFormat
Pixel format.
This structure stores compressed data.
int(* dxt5ys_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
static int hap_header_length(HapContext *ctx)