rawenc.c (3979B)
1 /* 2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved. 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 #include <stdbool.h> 13 #include "common/rawenc.h" 14 15 // Number of bytes to write per batch in write_greyscale. 16 #define BATCH_SIZE 8 17 18 // Interface to writing to either a file or MD5Context. Takes a pointer to 19 // either the file or MD5Context, the buffer, the size of each element, and 20 // number of elements to write. Note that size and nmemb (last two args) must 21 // be unsigned int, as the interface to MD5Update requires that. 22 typedef void (*WRITER)(void *, const uint8_t *, unsigned int, unsigned int); 23 24 static void write_file(void *fp, const uint8_t *buffer, unsigned int size, 25 unsigned int nmemb) { 26 fwrite(buffer, size, nmemb, (FILE *)fp); 27 } 28 29 static void write_md5(void *md5, const uint8_t *buffer, unsigned int size, 30 unsigned int nmemb) { 31 MD5Update((MD5Context *)md5, buffer, size * nmemb); 32 } 33 34 // Writes out n neutral chroma samples (for greyscale). 35 static void write_greyscale(const aom_image_t *img, int n, WRITER writer_func, 36 void *file_or_md5) { 37 // Batch 8 writes for low bit-depth, 4 writes for high bit-depth. 38 int bytes_per_sample; 39 union { 40 uint8_t u8[BATCH_SIZE]; 41 uint16_t u16[BATCH_SIZE / 2]; 42 } batched; 43 if (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) { 44 bytes_per_sample = 2; 45 for (int i = 0; i < BATCH_SIZE / 2; ++i) { 46 batched.u16[i] = 1 << (img->bit_depth - 1); 47 } 48 } else { 49 bytes_per_sample = 1; 50 for (int i = 0; i < BATCH_SIZE; ++i) { 51 batched.u8[i] = 0x80; 52 } 53 } 54 const int samples_per_batch = BATCH_SIZE / bytes_per_sample; 55 const int num_batched_writes = n / samples_per_batch; 56 for (int i = 0; i < num_batched_writes; ++i) { 57 writer_func(file_or_md5, batched.u8, sizeof(uint8_t), BATCH_SIZE); 58 } 59 const int remaining = n % samples_per_batch; 60 for (int i = 0; i < remaining; ++i) { 61 writer_func(file_or_md5, batched.u8, sizeof(uint8_t), bytes_per_sample); 62 } 63 } 64 65 // Encapsulates the logic for writing raw data to either an image file or 66 // to an MD5 context. 67 static void raw_write_image_file_or_md5(const aom_image_t *img, 68 const int *planes, const int num_planes, 69 void *file_or_md5, WRITER writer_func) { 70 const bool high_bitdepth = img->fmt & AOM_IMG_FMT_HIGHBITDEPTH; 71 const int bytes_per_sample = high_bitdepth ? 2 : 1; 72 for (int i = 0; i < num_planes; ++i) { 73 const int plane = planes[i]; 74 const int w = aom_img_plane_width(img, plane); 75 const int h = aom_img_plane_height(img, plane); 76 // If we're on a color plane and the output is monochrome, write a greyscale 77 // value. Since there are only YUV planes, compare against Y. 78 if (img->monochrome && plane != AOM_PLANE_Y) { 79 write_greyscale(img, w * h, writer_func, file_or_md5); 80 continue; 81 } 82 const unsigned char *buf = img->planes[plane]; 83 const int stride = img->stride[plane]; 84 for (int y = 0; y < h; ++y) { 85 writer_func(file_or_md5, buf, bytes_per_sample, w); 86 buf += stride; 87 } 88 } 89 } 90 91 void raw_write_image_file(const aom_image_t *img, const int *planes, 92 const int num_planes, FILE *file) { 93 raw_write_image_file_or_md5(img, planes, num_planes, file, write_file); 94 } 95 96 void raw_update_image_md5(const aom_image_t *img, const int *planes, 97 const int num_planes, MD5Context *md5) { 98 raw_write_image_file_or_md5(img, planes, num_planes, md5, write_md5); 99 }