y4m2tiff.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*Daala video codec
  2. Copyright (c) 2002-2012 Daala project contributors. All rights reserved.
  3. Redistribution and use in source and binary forms, with or without
  4. modification, are permitted provided that the following conditions are met:
  5. - Redistributions of source code must retain the above copyright notice, this
  6. list of conditions and the following disclaimer.
  7. - Redistributions in binary form must reproduce the above copyright notice,
  8. this list of conditions and the following disclaimer in the documentation
  9. and/or other materials provided with the distribution.
  10. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
  11. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  13. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  14. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  15. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  16. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  17. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  18. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  19. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #if !defined(_LARGEFILE_SOURCE)
  24. # define _LARGEFILE_SOURCE
  25. #endif
  26. #if !defined(_LARGEFILE64_SOURCE)
  27. # define _LARGEFILE64_SOURCE
  28. #endif
  29. #if !defined(_FILE_OFFSET_BITS)
  30. # define _FILE_OFFSET_BITS 64
  31. #endif
  32. #if !defined(_BSD_SOURCE)
  33. # define _BSD_SOURCE
  34. # define _DEFAULT_SOURCE
  35. #endif
  36. #include <stdint.h>
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <errno.h>
  41. #include <limits.h>
  42. #if !defined(_WIN32)
  43. # include <getopt.h>
  44. #else
  45. # include <fcntl.h>
  46. # include <io.h>
  47. # include "getopt.h"
  48. #endif
  49. #include <tiffio.h>
  50. #include <zlib.h>
  51. #include <ogg/os_types.h>
  52. #include "vidinput.h"
  53. #define OD_MINI(_a,_b) ((_a)<(_b)?(_a):(_b))
  54. #define OD_MAXI(_a,_b) ((_a)>(_b)?(_a):(_b))
  55. #define OD_CLAMPI(_a,_b,_c) (OD_MAXI(_a,OD_MINI(_b,_c)))
  56. #define OD_SIGNMASK(_a) (-((_a)<0))
  57. #define OD_FLIPSIGNI(_a,_b) ((_a)+OD_SIGNMASK(_b)^OD_SIGNMASK(_b))
  58. #define OD_DIV_ROUND(_x,_y) (((_x)+OD_FLIPSIGNI((_y)>>1,_x))/(_y))
  59. #define OD_CLAMP255(_x) ((unsigned char)((((_x)<0)-1)&((_x)|-((_x)>255))))
  60. enum{
  61. PIXEL_FMT_420,
  62. PIXEL_FMT_RESERVED,
  63. PIXEL_FMT_422,
  64. PIXEL_FMT_444
  65. };
  66. static const char *output_filename=NULL;
  67. const char *OPTSTRING="ho:";
  68. struct option OPTIONS[]={
  69. {"help",no_argument,NULL,'h'},
  70. {"output",required_argument,NULL,'o'},
  71. {NULL,0,NULL,0}
  72. };
  73. void **od_malloc_2d(size_t _height,size_t _width,size_t _sz){
  74. size_t rowsz;
  75. size_t colsz;
  76. size_t datsz;
  77. char *ret;
  78. colsz=_height*sizeof(void *);
  79. rowsz=_sz*_width;
  80. datsz=rowsz*_height;
  81. /*Alloc array and row pointers.*/
  82. ret=(char *)_ogg_malloc(datsz+colsz);
  83. /*Initialize the array.*/
  84. if(ret!=NULL){
  85. size_t i;
  86. void **p;
  87. char *datptr;
  88. p=(void **)ret;
  89. i=_height;
  90. for(datptr=ret+colsz;i-->0;p++,datptr+=rowsz)*p=(void *)datptr;
  91. }
  92. return (void **)ret;
  93. }
  94. void od_free_2d(void *_ptr){
  95. _ogg_free(_ptr);
  96. }
  97. static void usage(const char *_argv0){
  98. fprintf(stderr,
  99. "Usage: %s [options] <input>\n\n"
  100. "The <input> argument uses C printf format to represent a list of files,\n"
  101. " i.e. file-%%05d.tiff to look for files file00001.tiff to file99999.tiff.\n\n"
  102. "Options: \n\n"
  103. " -h --help Display this help and exit.\n"
  104. " -o --output <filename.tiff> Output file name (required).\n"
  105. " This uses a C printf format string to\n"
  106. " represent a list of files, i.e.\n"
  107. " file%%05d to write files file00001.tiff\n"
  108. " to file99999.tiff.\n",
  109. /*TODO: Currently only rec709 is supported.
  110. Also: RGB primaries and gamma (currently ignored).
  111. " --rec601 Use ITU-R BT.601 matrix.\n"
  112. " --rec709 Use ITU-R BT.709 matrix.\n"*/
  113. _argv0);
  114. }
  115. static void ycbcr_to_rgb(uint8_t* *_image,const video_input_info *_info,
  116. video_input_ycbcr _ycbcr){
  117. unsigned char *y_row;
  118. unsigned char *cb_row;
  119. unsigned char *cr_row;
  120. unsigned char *y;
  121. unsigned char *cb;
  122. unsigned char *cr;
  123. int y_stride;
  124. int cb_stride;
  125. int cr_stride;
  126. int width;
  127. int height;
  128. int hshift;
  129. int vshift;
  130. int pic_x;
  131. int pic_y;
  132. int i;
  133. int j;
  134. int xstride;
  135. width=_info->pic_w;
  136. height=_info->pic_h;
  137. xstride=(_info->depth>8)?2:1;
  138. hshift=!(_info->pixel_fmt&1);
  139. vshift=!(_info->pixel_fmt&2);
  140. y_stride=_ycbcr[0].stride;
  141. cb_stride=_ycbcr[1].stride;
  142. cr_stride=_ycbcr[2].stride;
  143. pic_x=_info->pic_x;
  144. pic_y=_info->pic_y;
  145. y_row=_ycbcr[0].data+pic_y*y_stride;
  146. cb_row=_ycbcr[1].data+(pic_y>>vshift)*cb_stride;
  147. cr_row=_ycbcr[2].data+(pic_y>>vshift)*cr_stride;
  148. /*Chroma up-sampling is just done with a box filter.
  149. This is very likely what will actually be used in practice on a real
  150. display, and also removes one more layer to search in for the source of
  151. artifacts.
  152. As an added bonus, it's dead simple.*/
  153. for(j=0;j<height;j++){
  154. int dc;
  155. y=y_row+_info->pic_x;
  156. cb=cb_row+(pic_x>>hshift);
  157. cr=cr_row+(pic_x>>hshift);
  158. for(i=0;i<6*width;){
  159. int64_t yval;
  160. int64_t cbval;
  161. int64_t crval;
  162. unsigned rval;
  163. unsigned gval;
  164. unsigned bval;
  165. int extrabits;
  166. extrabits=_info->depth-8;
  167. if(_info->depth<=8){
  168. yval=*y-16;
  169. cbval=*cb-128;
  170. crval=*cr-128;
  171. }
  172. else {
  173. yval = *y + (*(y+1)<<8);
  174. cbval = *cb + (*(cb+1)<<8);
  175. crval = *cr + (*(cr+1)<<8);
  176. yval=(yval-(16<<extrabits));
  177. cbval=(cbval-(128<<extrabits));
  178. crval=(crval-(128<<extrabits));
  179. }
  180. /*This is intentionally slow and very accurate.*/
  181. rval=OD_CLAMPI(0,(int32_t)OD_DIV_ROUND(
  182. 2916394880000LL*yval+4490222169144LL*crval,9745792000LL<<extrabits),
  183. 65535);
  184. gval=OD_CLAMPI(0,(int32_t)OD_DIV_ROUND(
  185. 2916394880000LL*yval-534117096223LL*cbval-1334761232047LL*crval,
  186. 9745792000LL<<extrabits),65535);
  187. bval=OD_CLAMPI(0,(int32_t)OD_DIV_ROUND(
  188. 2916394880000LL*yval+5290866304968LL*cbval,9745792000LL<<extrabits),
  189. 65535);
  190. _image[j][i++]=(unsigned char)(rval&0xFF);
  191. _image[j][i++]=(unsigned char)(rval>>8);
  192. _image[j][i++]=(unsigned char)(gval&0xFF);
  193. _image[j][i++]=(unsigned char)(gval>>8);
  194. _image[j][i++]=(unsigned char)(bval&0xFF);
  195. _image[j][i++]=(unsigned char)(bval>>8);
  196. dc=y-y_row&(xstride)|1-hshift;
  197. y+=xstride;
  198. cb+=dc;
  199. cr+=dc;
  200. }
  201. dc=-(pic_y+j&1|1-vshift);
  202. y_row+=y_stride;
  203. cb_row+=dc&cb_stride;
  204. cr_row+=dc&cr_stride;
  205. }
  206. }
  207. static int write_tiff(TIFF *_fout,const video_input_info *_info,video_input_ycbcr _ycbcr){
  208. uint8_t **image;
  209. int width;
  210. int height;
  211. int row;
  212. width=_info->pic_w;
  213. height=_info->pic_h;
  214. image=(uint8_t **)od_malloc_2d(height,6*width,sizeof(**image));
  215. ycbcr_to_rgb(image,_info,_ycbcr);
  216. for (row = 0; row < height; row++) {
  217. TIFFWriteScanline(_fout, image[row], row, 0);
  218. }
  219. od_free_2d(image);
  220. return 0;
  221. }
  222. int main(int _argc,char **_argv){
  223. video_input vid;
  224. video_input_info info;
  225. video_input_ycbcr ycbcr;
  226. TIFF *fout;
  227. FILE *fin;
  228. const char *input_filename;
  229. int i;
  230. #ifdef _WIN32
  231. /*We need to set stdin/stdout to binary mode.
  232. Damn Windows.*/
  233. /*Beware the evil ifdef.
  234. We avoid these where we can, but this one we cannot.
  235. Don't add any more, you'll probably go to hell if you do.*/
  236. _setmode(_fileno(stdin),_O_BINARY);
  237. _setmode(_fileno(stdout),_O_BINARY);
  238. #endif
  239. for(;;){
  240. int long_option_index;
  241. int c;
  242. c=getopt_long(_argc,_argv,OPTSTRING,OPTIONS,&long_option_index);
  243. if(c==EOF)break;
  244. switch(c){
  245. case 'h':{
  246. usage(_argv[0]);
  247. return EXIT_SUCCESS;
  248. }
  249. case 'o':{
  250. output_filename=optarg;
  251. break;
  252. }
  253. default:{
  254. usage(_argv[0]);
  255. return EXIT_FAILURE;
  256. }
  257. }
  258. }
  259. if(_argc<3){
  260. usage(_argv[0]);
  261. return EXIT_FAILURE;
  262. }
  263. input_filename=_argv[optind];
  264. if(input_filename==NULL){
  265. fprintf(stderr,"No input file specified. Run with -h for help.\n");
  266. return EXIT_FAILURE;
  267. }
  268. fin=strcmp(input_filename,"-")==0?stdin:fopen(input_filename,"rb");
  269. if(fin==NULL){
  270. fprintf(stderr,"Could not open input file \"%s\": %s\n",
  271. input_filename,strerror(errno));
  272. return EXIT_FAILURE;
  273. }
  274. if(video_input_open(&vid,fin)<0)return EXIT_FAILURE;
  275. if(output_filename==NULL){
  276. fprintf(stderr,"No output file specified. Run with -h for help.\n");
  277. return EXIT_FAILURE;
  278. }
  279. video_input_get_info(&vid,&info);
  280. for(i=0;video_input_fetch_frame(&vid,ycbcr,NULL)>0;i++){
  281. fout=TIFFOpen(output_filename, "w");
  282. TIFFSetField(fout, TIFFTAG_IMAGELENGTH, info.pic_h);
  283. TIFFSetField(fout, TIFFTAG_IMAGEWIDTH, info.pic_w);
  284. TIFFSetField(fout, TIFFTAG_BITSPERSAMPLE, 16);
  285. TIFFSetField(fout, TIFFTAG_SAMPLESPERPIXEL, 3);
  286. TIFFSetField(fout, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  287. TIFFSetField(fout, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
  288. TIFFSetField(fout, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
  289. write_tiff(fout,&info,ycbcr);
  290. TIFFClose(fout);
  291. }
  292. video_input_close(&vid);
  293. return EXIT_SUCCESS;
  294. }