png2y4m.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  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. /*Adapted from png2theora, part of the OggTheora software codec source code.
  21. The Theora source code is copyright (C) 2002-2009
  22. by the Xiph.Org Foundation and contributors http://www.xiph.org/
  23. Based on code from Vegard Nossum.*/
  24. #if !defined(_LARGEFILE_SOURCE)
  25. # define _LARGEFILE_SOURCE
  26. #endif
  27. #if !defined(_LARGEFILE64_SOURCE)
  28. # define _LARGEFILE64_SOURCE
  29. #endif
  30. #if !defined(_FILE_OFFSET_BITS)
  31. # define _FILE_OFFSET_BITS 64
  32. #endif
  33. #if !defined(_BSD_SOURCE)
  34. # define _BSD_SOURCE
  35. #endif
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <errno.h>
  40. #include <dirent.h>
  41. #include <limits.h>
  42. #if !defined(_WIN32)
  43. # include <getopt.h>
  44. # include <unistd.h>
  45. #else
  46. # include <fnctl.h>
  47. # include <io.h>
  48. # include "getopt.h"
  49. #endif
  50. #include <libgen.h>
  51. #include <png.h>
  52. #include "kiss99.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 *CHROMA_TAGS[4]={" C420jpeg",""," C422jpeg"," C444"};
  67. static const char *output_filename=NULL;
  68. static int fps_numerator=24;
  69. static int fps_denominator=1;
  70. static int aspect_numerator=0;
  71. static int aspect_denominator=0;
  72. static int pixel_format=PIXEL_FMT_420;
  73. static char *input_filter;
  74. const char *OPTSTRING="o:hs:S:f:F:\5\6";
  75. struct option OPTIONS[]={
  76. {"output",required_argument,NULL,'o'},
  77. {"help",no_argument,NULL,'h'},
  78. {"chroma-444",no_argument,NULL,'\5'},
  79. {"chroma-422",no_argument,NULL,'\6'},
  80. {"aspect-numerator",required_argument,NULL,'s'},
  81. {"aspect-denominator",required_argument,NULL,'S'},
  82. {"framerate-numerator",required_argument,NULL,'f'},
  83. {"framerate-denominator",required_argument,NULL,'F'},
  84. {NULL,0,NULL,0}
  85. };
  86. static void usage(const char *_argv0){
  87. fprintf(stderr,
  88. "Usage: %s [options] <input>\n\n"
  89. "The <input> argument uses a C printf format string to represent a list of\n"
  90. "files, i.e., file%%05d.png to look for files file00000.png to\n"
  91. "file99999.png.\n\n"
  92. "Options: \n\n"
  93. " -h --help Display this help and exit.\n"
  94. " -o --output <filename.y4m> Output file name (required).\n"
  95. " --chroma-444 Use 4:4:4 chroma subsampling.\n"
  96. " --chroma-422 Use 4:2:2 chroma subsampling.\n"
  97. " (4:2:0 is default).\n\n"
  98. /*TODO: Currently only rec709 is supported.
  99. Also: RGB primaries and gamma (currently ignored).
  100. " --rec601 Use ITU-R BT.601 matrix.\n"
  101. " --rec709 Use ITU-R BT.709 matrix.\n"*/
  102. " -s --aspect-numerator <n> Aspect ratio numerator, default is 0.\n"
  103. " -S --aspect-denominator <n> Aspect ratio denominator, default is 0.\n"
  104. " -f --framerate-numerator <n> Framerate numerator (default 24).\n"
  105. " Determines the frame rate in frames per\n"
  106. " second when divided by the framerate\n"
  107. " denominator.\n"
  108. " -F --framerate-denominator <n> Frame rate denominator (default 1).\n",
  109. _argv0);
  110. }
  111. #ifdef _WIN32
  112. int alphasort(const void *_a, const void *_b){
  113. return strcoll((*(const struct dirent **)_a)->d_name,
  114. (*(const struct dirent **)_b)->d_name);
  115. }
  116. typedef int (*compar_func)(const void *,const void *);
  117. int scandir(const char *_dirp,struct dirent ***_namelist,
  118. int (*_filter)(const struct dirent *),
  119. int (*_compar)(const struct dirent *,const struct dirent *)){
  120. DIR *d;
  121. struct dirent *entry;
  122. size_t entry_sz;
  123. struct dirent **names;
  124. int nnames;
  125. int cnames;
  126. d=opendir(dir);
  127. if(d==NULL)return -1;
  128. names=NULL;
  129. nnames=cnames=0;
  130. while((entry=readdir(d))!=NULL){
  131. if(_filter==NULL||(*_filter)(entry)){
  132. if(nnames>=cnames){
  133. cnames=cnames<<1|1;
  134. names=(struct dirent **)realloc(names,cnames*sizeof(*names));
  135. }
  136. entry_sz=sizeof(*entry)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
  137. names[nnames]=(struct dirent *)malloc(entry_sz);
  138. memcpy(names[nnames],entry,entry_sz);
  139. nnames++;
  140. }
  141. }
  142. if(closedir(d)<0)return -1;
  143. if(nnames==0)return -1;
  144. if(_compar!=NULL)qsort(names,nnames,sizeof(*names),(compar_func)_compar);
  145. *_namelist=(struct dirent **)realloc(names,nnames*sizeof(*names));
  146. return nnames;
  147. }
  148. #endif
  149. typedef struct img_plane img_plane;
  150. struct img_plane{
  151. int width;
  152. int height;
  153. int stride;
  154. unsigned char *data;
  155. };
  156. /*Generate a triangular deviate with zero mean and range [-_range,_range].*/
  157. static int32_t triangle_rand(kiss99_ctx *_kiss,int32_t _range){
  158. uint32_t m;
  159. uint32_t r1;
  160. uint32_t r2;
  161. _range++;
  162. m=0xFFFFFFFFU/_range*_range;
  163. do r1=kiss99_rand(_kiss);
  164. while(r1>=m);
  165. do r2=kiss99_rand(_kiss);
  166. while(r2>=m);
  167. return (int32_t)(r1%_range)-(int32_t)(r2%_range);
  168. }
  169. /*WARNING: The constants in the following code are hard-coded for the BT.709
  170. matrices.*/
  171. /*Adds triangle-shaped dither to an RGB pixel, but aligned with the Y'CbCr axes
  172. and scaled with the quantizer in that space.
  173. The dither has to be added in Y'CbCr space because that's where we're
  174. quantizing, but projecting it back allows us to measure error in the RGB
  175. space, which is especially useful for handling things like subsampling.*/
  176. static void get_dithered_pixel(int32_t *_r,int32_t *_g,int32_t *_b,
  177. const png_byte *_rgb,int64_t _yd,int64_t _cbd,int64_t _crd){
  178. int32_t r;
  179. int32_t g;
  180. int32_t b;
  181. r=_rgb[0]*256+_rgb[1];
  182. g=_rgb[2]*256+_rgb[3];
  183. b=_rgb[4]*256+_rgb[5];
  184. r+=(int32_t)OD_DIV_ROUND(2*_yd+3*_crd,8176000);
  185. g+=(int32_t)OD_DIV_ROUND(2384*_yd+361*_cbd+1063*_crd,9745792000LL);
  186. b+=(int32_t)OD_DIV_ROUND(2*_yd+3*_cbd,8176000);
  187. *_r=r;
  188. *_g=g;
  189. *_b=b;
  190. }
  191. static int calc_y(int32_t _r,int32_t _g,int32_t _b,int _cb,int _cr){
  192. int64_t chroma_r;
  193. int64_t chroma_g;
  194. int64_t chroma_b;
  195. int64_t r_res;
  196. int64_t g_res;
  197. int64_t b_res;
  198. int64_t yn;
  199. int64_t err0;
  200. int64_t err1;
  201. int32_t r;
  202. int32_t g;
  203. int32_t b;
  204. int y0;
  205. _cb-=128;
  206. _cr-=128;
  207. chroma_r=4490222169144LL*_cr;
  208. chroma_g=-534117096223LL*_cb-1334761232047LL*_cr;
  209. chroma_b=5290866304968LL*_cb;
  210. r_res=_r*9745792000LL-chroma_r+4096>>13;
  211. g_res=_g*9745792000LL-chroma_g+4096>>13;
  212. b_res=_b*9745792000LL-chroma_b+4096>>13;
  213. /*Take the floor here instead of rounding; we'll consider both possible
  214. values.*/
  215. yn=1063*r_res+3576*g_res+361*b_res;
  216. y0=(int)((yn-(1780026171874LL&OD_SIGNMASK(yn)))/1780026171875LL);
  217. /*Clamp before adding the offset.
  218. We clamp to 238 instead of 239 to ensure we can always add one and stay in
  219. range.*/
  220. y0=OD_CLAMPI(-16,y0,238);
  221. /*Check the reconstruction error with y0 after rounding and clamping.*/
  222. r=OD_CLAMPI(0,
  223. (int32_t)OD_DIV_ROUND(2916394880000LL*y0+chroma_r,9745792000LL),65535);
  224. g=OD_CLAMPI(0,
  225. (int32_t)OD_DIV_ROUND(2916394880000LL*y0+chroma_g,9745792000LL),65535);
  226. b=OD_CLAMPI(0,
  227. (int32_t)OD_DIV_ROUND(2916394880000LL*y0+chroma_b,9745792000LL),65535);
  228. err0=(_r-r)*(_r-r)+(_g-g)*(_g-g)+(_b-b)*(_b-b);
  229. /*Check the reconstruction error with y0+1 after rounding and clamping.*/
  230. r=OD_CLAMPI(0,
  231. (int32_t)OD_DIV_ROUND(2916394880000LL*(y0+1)+chroma_r,9745792000LL),65535);
  232. g=OD_CLAMPI(0,
  233. (int32_t)OD_DIV_ROUND(2916394880000LL*(y0+1)+chroma_g,9745792000LL),65535);
  234. b=OD_CLAMPI(0,
  235. (int32_t)OD_DIV_ROUND(2916394880000LL*(y0+1)+chroma_b,9745792000LL),65535);
  236. err1=(_r-r)*(_r-r)+(_g-g)*(_g-g)+(_b-b)*(_b-b);
  237. if(err1<err0)y0++;
  238. /*In the unlikely event there's a tie, round to even.*/
  239. else if(err1==err0)y0+=y0&1;
  240. return y0+16;
  241. }
  242. static void rgb_to_ycbcr(img_plane _ycbcr[3],png_bytep *_png){
  243. kiss99_ctx kiss;
  244. unsigned char *ydata;
  245. unsigned char *cbdata;
  246. unsigned char *crdata;
  247. int ystride;
  248. int cbstride;
  249. int crstride;
  250. int hstep;
  251. int vstep;
  252. int w;
  253. int h;
  254. int i;
  255. int j;
  256. w=_ycbcr[0].width;
  257. h=_ycbcr[0].height;
  258. ystride=_ycbcr[0].stride;
  259. ydata=_ycbcr[0].data;
  260. cbstride=_ycbcr[1].stride;
  261. cbdata=_ycbcr[1].data;
  262. crstride=_ycbcr[2].stride;
  263. crdata=_ycbcr[2].data;
  264. hstep=pixel_format&1;
  265. vstep=pixel_format&2;
  266. kiss99_srand(&kiss,NULL,0);
  267. for(j=0;j<h;j+=2){
  268. for(i=0;i<w;i+=2){
  269. int32_t yd[4];
  270. int32_t cbd[4];
  271. int32_t crd[4];
  272. int32_t r0;
  273. int32_t g0;
  274. int32_t b0;
  275. int32_t r1;
  276. int32_t g1;
  277. int32_t b1;
  278. int32_t r2;
  279. int32_t g2;
  280. int32_t b2;
  281. int32_t r3;
  282. int32_t g3;
  283. int32_t b3;
  284. int64_t rsum;
  285. int64_t gsum;
  286. int64_t bsum;
  287. int k;
  288. int cb;
  289. int cr;
  290. /*This often generates more dither values than we use, but keeps them in
  291. sync for the luma plane across the different pixel formats.*/
  292. for(k=0;k<4;k++){
  293. /*The size of the dither here is chosen to be the largest divisor of
  294. all the corresponding coefficients in the transform that still fits
  295. in 31 bits.*/
  296. yd[k]=triangle_rand(&kiss,1223320000);
  297. cbd[k]=triangle_rand(&kiss,1479548743);
  298. crd[k]=triangle_rand(&kiss,1255654969);
  299. }
  300. get_dithered_pixel(&r0,&g0,&b0,_png[j]+6*i,yd[0],cbd[0],crd[0]);
  301. if(i+1<w){
  302. get_dithered_pixel(&r1,&g1,&b1,_png[j]+6*(i+1),
  303. yd[1],cbd[hstep],crd[hstep]);
  304. }
  305. else{
  306. r1=r0;
  307. g1=g0;
  308. b1=b0;
  309. }
  310. if(j+1<h){
  311. get_dithered_pixel(&r2,&g2,&b2,_png[j+1]+6*i,
  312. yd[2],cbd[vstep],crd[vstep]);
  313. if(i+1<w){
  314. get_dithered_pixel(&r3,&g3,&b3,_png[j+1]+6*(i+1),
  315. yd[3],cbd[vstep+hstep],crd[vstep+hstep]);
  316. }
  317. else{
  318. r3=r2;
  319. g3=g2;
  320. b3=b2;
  321. }
  322. }
  323. else{
  324. r2=r0;
  325. g2=g0;
  326. b2=b0;
  327. r3=r1;
  328. g3=g1;
  329. b3=b1;
  330. }
  331. if(pixel_format==PIXEL_FMT_420){
  332. rsum=r0+r1+r2+r3;
  333. gsum=g0+g1+g2+g3;
  334. bsum=b0+b1+b2+b3;
  335. cb=OD_CLAMP255(
  336. OD_DIV_ROUND(-29764*rsum-100128*gsum+129892*bsum,304016865)+128);
  337. cr=OD_CLAMP255(
  338. OD_DIV_ROUND(110236*rsum-100128*gsum-10108*bsum,258011295)+128);
  339. cbdata[(j>>1)*cbstride+(i>>1)]=(unsigned char)cb;
  340. crdata[(j>>1)*crstride+(i>>1)]=(unsigned char)cr;
  341. ydata[j*ystride+i]=calc_y(r0,g0,b0,cb,cr);
  342. if(i+1<w)ydata[j*ystride+i+1]=calc_y(r1,g1,b1,cb,cr);
  343. if(j+1<h){
  344. ydata[(j+1)*ystride+i]=calc_y(r2,g2,b2,cb,cr);
  345. if(i+1<w)ydata[(j+1)*ystride+i+1]=calc_y(r3,g3,b3,cb,cr);
  346. }
  347. }
  348. else if(pixel_format==PIXEL_FMT_422){
  349. rsum=r0+r1;
  350. gsum=g0+g1;
  351. bsum=b0+b1;
  352. cb=OD_CLAMP255(
  353. OD_DIV_ROUND(-59528*rsum-200256*gsum+259784*bsum,304016865)+128);
  354. cr=OD_CLAMP255(
  355. OD_DIV_ROUND(220472*rsum-200256*gsum-20216*bsum,258011295)+128);
  356. cbdata[j*cbstride+(i>>1)]=(unsigned char)cb;
  357. crdata[j*crstride+(i>>1)]=(unsigned char)cr;
  358. ydata[j*ystride+i]=calc_y(r0,g0,b0,cb,cr);
  359. if(i+1<w)ydata[j*ystride+i+1]=calc_y(r1,g1,b1,cb,cr);
  360. if(j+1<h){
  361. rsum=r2+r3;
  362. gsum=g2+g3;
  363. bsum=b2+b3;
  364. cb=OD_CLAMP255(
  365. OD_DIV_ROUND(-59528*rsum-200256*gsum+259784*bsum,304016865)+128);
  366. cr=OD_CLAMP255(
  367. OD_DIV_ROUND(220472*rsum-200256*gsum-20216*bsum,258011295)+128);
  368. cbdata[(j+1)*cbstride+(i>>1)]=(unsigned char)cb;
  369. crdata[(j+1)*crstride+(i>>1)]=(unsigned char)cr;
  370. ydata[(j+1)*ystride+i]=calc_y(r2,g2,b2,cb,cr);
  371. if(i+1<w)ydata[(j+1)*ystride+i+1]=calc_y(r3,g3,b3,cb,cr);
  372. }
  373. }
  374. else{
  375. rsum=r0;
  376. gsum=g0;
  377. bsum=b0;
  378. cb=OD_CLAMP255(
  379. OD_DIV_ROUND(-119056*rsum-400512*gsum+519568*bsum,304016865)+128);
  380. cr=OD_CLAMP255(
  381. OD_DIV_ROUND(440944*rsum-400512*gsum-40432*bsum,258011295)+128);
  382. cbdata[j*cbstride+i]=(unsigned char)cb;
  383. crdata[j*crstride+i]=(unsigned char)cr;
  384. ydata[j*ystride+i]=calc_y(r0,g0,b0,cb,cr);
  385. if(i+1<w){
  386. rsum=r1;
  387. gsum=g1;
  388. bsum=b1;
  389. cb=OD_CLAMP255(
  390. OD_DIV_ROUND(-119056*rsum-400512*gsum+519568*bsum,304016865)+128);
  391. cr=OD_CLAMP255(
  392. OD_DIV_ROUND(440944*rsum-400512*gsum-40432*bsum,258011295)+128);
  393. cbdata[j*cbstride+i+1]=(unsigned char)cb;
  394. crdata[j*crstride+i+1]=(unsigned char)cr;
  395. ydata[j*ystride+i+1]=calc_y(r1,g1,b1,cb,cr);
  396. }
  397. if(j+1<h){
  398. rsum=r2;
  399. gsum=g2;
  400. bsum=b2;
  401. cb=OD_CLAMP255(
  402. OD_DIV_ROUND(-119056*rsum-400512*gsum+519568*bsum,304016865)+128);
  403. cr=OD_CLAMP255(
  404. OD_DIV_ROUND(440944*rsum-400512*gsum-40432*bsum,258011295)+128);
  405. cbdata[(j+1)*cbstride+i]=(unsigned char)cb;
  406. crdata[(j+1)*crstride+i]=(unsigned char)cr;
  407. ydata[(j+1)*ystride+i]=calc_y(r2,g2,b2,cb,cr);
  408. if(i+1<w){
  409. rsum=r3;
  410. gsum=g3;
  411. bsum=b3;
  412. cb=OD_CLAMP255(
  413. OD_DIV_ROUND(-119056*rsum-400512*gsum+519568*bsum,304016865)+128);
  414. cr=OD_CLAMP255(
  415. OD_DIV_ROUND(440944*rsum-400512*gsum-40432*bsum,258011295)+128);
  416. cbdata[(j+1)*cbstride+i+1]=(unsigned char)cb;
  417. crdata[(j+1)*crstride+i+1]=(unsigned char)cr;
  418. ydata[(j+1)*ystride+i+1]=calc_y(r3,g3,b3,cb,cr);
  419. }
  420. }
  421. }
  422. }
  423. }
  424. }
  425. static void png_read(png_structp _png,png_bytep _data,png_size_t _sz){
  426. size_t ret;
  427. ret=fread(_data,_sz,1,(FILE *)png_get_io_ptr(_png));
  428. if(ret!=1)png_error(_png,"Read Error");
  429. }
  430. static int read_png(img_plane _ycbcr[3],FILE *_fin){
  431. unsigned char header[8];
  432. png_structp png;
  433. png_infop info;
  434. png_infop end;
  435. png_bytep img;
  436. png_bytep *rows;
  437. png_color_16p bkgd;
  438. png_uint_32 width;
  439. png_uint_32 height;
  440. int bit_depth;
  441. int color_type;
  442. int interlace_type;
  443. int compression_type;
  444. int filter_method;
  445. int hshift;
  446. int vshift;
  447. png_uint_32 i;
  448. png_uint_32 j;
  449. if(fread(header,8,1,_fin)<1){
  450. fprintf(stderr,"Error reading from file.\n");
  451. return -EINVAL;
  452. }
  453. if(png_sig_cmp(header,0,8)){
  454. fprintf(stderr,"Error: Not a PNG.\n");
  455. return -EINVAL;
  456. }
  457. png=png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
  458. if(png==NULL){
  459. fprintf(stderr,"Error: %s\n",strerror(ENOMEM));
  460. return -ENOMEM;
  461. }
  462. info=png_create_info_struct(png);
  463. if(info==NULL){
  464. fprintf(stderr,"Error: %s\n",strerror(ENOMEM));
  465. png_destroy_read_struct(&png,NULL,NULL);
  466. return -ENOMEM;
  467. }
  468. end=png_create_info_struct(png);
  469. if(end==NULL){
  470. fprintf(stderr,"Error: %s\n",strerror(ENOMEM));
  471. png_destroy_read_struct(&png,&info,NULL);
  472. return -EINVAL;
  473. }
  474. rows=NULL;
  475. img=NULL;
  476. if(setjmp(png_jmpbuf(png))){
  477. png_free(png,rows);
  478. free(img);
  479. png_destroy_read_struct(&png,&info,&end);
  480. return -EINVAL;
  481. }
  482. png_set_read_fn(png,_fin,png_read);
  483. png_set_sig_bytes(png,8);
  484. png_read_info(png,info);
  485. png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,
  486. &interlace_type,&compression_type,&filter_method);
  487. if(width>INT_MAX||height>INT_MAX||width*(png_size_t)height>INT_MAX){
  488. png_destroy_read_struct(&png,&info,&end);
  489. return -EINVAL;
  490. }
  491. png_set_expand(png);
  492. if(bit_depth<8)png_set_packing(png);
  493. if(!(color_type&PNG_COLOR_MASK_COLOR))png_set_gray_to_rgb(png);
  494. if(png_get_bKGD(png,info,&bkgd)){
  495. png_set_background(png,bkgd,PNG_BACKGROUND_GAMMA_FILE,1,1.0);
  496. }
  497. /*Note that color_type 2 and 3 can also have alpha, despite not setting the
  498. PNG_COLOR_MASK_ALPHA bit.
  499. We always strip it to prevent libpng from overrunning our buffer.*/
  500. png_set_strip_alpha(png);
  501. img=(png_bytep)malloc(height*width*6*sizeof(*img));
  502. rows=(png_bytep *)png_malloc(png,height*sizeof(*rows));
  503. for(j=0;j<height;j++)rows[j]=img+j*width*6;
  504. png_read_image(png,rows);
  505. png_read_end(png,end);
  506. /*If the image wasn't 16-bit, expand it so it is.
  507. We do this by duplicating the high byte, so that, e.g., 0 maps to 0 and
  508. 255 maps to 65535.
  509. This is also nicely endian-independent.*/
  510. if(bit_depth<16){
  511. for(j=0;j<height;j++){
  512. for(i=3*width;i-->0;)rows[j][2*i]=rows[j][2*i+1]=rows[j][i];
  513. }
  514. }
  515. hshift=!(pixel_format&1);
  516. vshift=!(pixel_format&2);
  517. if(_ycbcr[0].data==NULL){
  518. _ycbcr[0].width=(int)width;
  519. _ycbcr[0].height=(int)height;
  520. _ycbcr[0].stride=(int)width;
  521. _ycbcr[1].width=(int)(width+hshift>>hshift);
  522. _ycbcr[1].height=(int)(height+vshift>>vshift);
  523. _ycbcr[1].stride=_ycbcr[1].width;
  524. _ycbcr[2].width=_ycbcr[1].width;
  525. _ycbcr[2].stride=_ycbcr[1].stride;
  526. _ycbcr[2].height=_ycbcr[1].height;
  527. _ycbcr[0].data=(unsigned char *)malloc(_ycbcr[0].stride*_ycbcr[0].height);
  528. _ycbcr[1].data=(unsigned char *)malloc(_ycbcr[1].stride*_ycbcr[1].height);
  529. _ycbcr[2].data=(unsigned char *)malloc(_ycbcr[2].stride*_ycbcr[2].height);
  530. }
  531. else if(_ycbcr[0].width!=(int)width||_ycbcr[0].height!=(int)height){
  532. fprintf(stderr,"Input size %ix%i does not match %ix%i\n",
  533. (int)width,(int)height,_ycbcr[0].width,_ycbcr[0].height);
  534. return -EINVAL;
  535. }
  536. rgb_to_ycbcr(_ycbcr,rows);
  537. png_free(png,rows);
  538. free(img);
  539. png_destroy_read_struct(&png,&info,&end);
  540. return 0;
  541. }
  542. static int include_files(const struct dirent *de){
  543. char name[8192];
  544. int number;
  545. number=-1;
  546. sscanf(de->d_name,input_filter,&number);
  547. snprintf(name,8191,input_filter,number);
  548. return !strcmp(name,de->d_name);
  549. }
  550. static FILE *open_png_file(const char *_input_directory,const char *_name){
  551. FILE *fin;
  552. char input_filename[8192];
  553. snprintf(input_filename,8191,"%s/%s",_input_directory,_name);
  554. fin=fopen(input_filename,"rb");
  555. if(fin==NULL){
  556. fprintf(stderr,"Error opening \"%s\": %s\n",input_filename,strerror(errno));
  557. }
  558. return fin;
  559. }
  560. int main(int _argc,char **_argv){
  561. img_plane ycbcr[3];
  562. FILE *fout;
  563. FILE *fin;
  564. struct dirent **png_files;
  565. int npng_files;
  566. char *input_mask;
  567. char *input_directory;
  568. char *scratch;
  569. int i;
  570. #ifdef _WIN32
  571. /*We need to set stdin/stdout to binary mode.
  572. Damn Windows.*/
  573. /*Beware the evil ifdef.
  574. We avoid these where we can, but this one we cannot.
  575. Don't add any more, you'll probably go to hell if you do.*/
  576. _setmode(_fileno(stdin),_O_BINARY);
  577. _setmode(_fileno(stdout),_O_BINARY);
  578. #endif
  579. for(;;){
  580. int long_option_index;
  581. int c;
  582. c=getopt_long(_argc,_argv,OPTSTRING,OPTIONS,&long_option_index);
  583. if(c==EOF)break;
  584. switch(c){
  585. case 'h':{
  586. usage(_argv[0]);
  587. return EXIT_SUCCESS;
  588. }
  589. case 'o':{
  590. output_filename=optarg;
  591. break;
  592. }
  593. case 's':aspect_numerator=atol(optarg);break;
  594. case 'S':aspect_denominator=atol(optarg);break;
  595. case 'f':fps_numerator=atol(optarg);break;
  596. case 'F':fps_denominator=atol(optarg);break;
  597. case '\5':pixel_format=PIXEL_FMT_444;break;
  598. case '\6':pixel_format=PIXEL_FMT_422;break;
  599. default:{
  600. usage(_argv[0]);
  601. return EXIT_FAILURE;
  602. }
  603. }
  604. }
  605. if(_argc<3){
  606. usage(_argv[0]);
  607. return EXIT_FAILURE;
  608. }
  609. input_mask=_argv[optind];
  610. if(input_mask==NULL){
  611. fprintf(stderr,"No input files specified. Run with -h for help.\n");
  612. return EXIT_FAILURE;
  613. }
  614. ycbcr[0].data=NULL;
  615. if(strcmp(input_mask,"-")!=0){
  616. /*dirname() and basename() must operate on scratch strings.*/
  617. scratch=strdup(input_mask);
  618. input_directory=strdup(dirname(scratch));
  619. free(scratch);
  620. scratch=strdup(input_mask);
  621. input_filter=strdup(basename(scratch));
  622. free(scratch);
  623. npng_files=scandir(input_directory,&png_files,include_files,alphasort);
  624. if(npng_files<=0){
  625. fprintf(stderr,"No input files found. Run with -h for help.\n");
  626. return EXIT_FAILURE;
  627. }
  628. fin=open_png_file(input_directory,png_files[0]->d_name);
  629. if(fin==NULL)return EXIT_FAILURE;
  630. }
  631. else{
  632. /*Don't set npng_files to 1 to avoid trying to free a non-existant dirent
  633. later.*/
  634. npng_files=0;
  635. png_files=NULL;
  636. input_directory=NULL;
  637. fin=stdin;
  638. }
  639. if(output_filename==NULL){
  640. fprintf(stderr,"No output file specified. Run with -h for help.\n");
  641. return EXIT_FAILURE;
  642. }
  643. fout=strcmp(output_filename,"-")==0?stdout:fopen(output_filename,"wb");
  644. if(fout==NULL){
  645. fprintf(stderr,"Error opening output file \"%s\".\n",output_filename);
  646. return 1;
  647. }
  648. if(read_png(ycbcr,fin)<0)return EXIT_FAILURE;
  649. if(fin!=stdin)fclose(fin);
  650. fprintf(stderr,"%d frames, %dx%d\n",
  651. OD_MAXI(npng_files,1),ycbcr[0].width,ycbcr[0].height);
  652. /*Write the Y4M header.*/
  653. fprintf(fout,"YUV4MPEG2 W%i H%i F%i:%i Ip A%i:%i%s\n",
  654. ycbcr[0].width,ycbcr[0].height,fps_numerator,fps_denominator,
  655. aspect_numerator,aspect_denominator,CHROMA_TAGS[pixel_format]);
  656. i=0;
  657. do{
  658. int pli;
  659. int j;
  660. if(i>0){
  661. fin=open_png_file(input_directory,png_files[i]->d_name);
  662. if(fin==NULL)return EXIT_FAILURE;
  663. fprintf(stderr,"%s\n",png_files[i]->d_name);
  664. if(read_png(ycbcr,fin)<0)return EXIT_FAILURE;
  665. if(fin!=stdin)fclose(fin);
  666. }
  667. else if(npng_files>0)fprintf(stderr,"%s\n",png_files[0]->d_name);
  668. fprintf(fout,"FRAME\n");
  669. for(pli=0;pli<3;pli++){
  670. for(j=0;j<ycbcr[pli].height;j++){
  671. if(fwrite(ycbcr[pli].data+j*ycbcr[pli].stride,
  672. ycbcr[pli].width,1,fout)<1){
  673. fprintf(stderr,"Error writing to \"%s\".\n",output_filename);
  674. return EXIT_FAILURE;
  675. }
  676. }
  677. }
  678. }
  679. while(++i<npng_files);
  680. free(ycbcr[2].data);
  681. free(ycbcr[1].data);
  682. free(ycbcr[0].data);
  683. if(fout!=stdout)fclose(fout);
  684. else fflush(fout);
  685. while(npng_files-->0)free(png_files[npng_files]);
  686. free(png_files);
  687. free(input_filter);
  688. free(input_directory);
  689. return EXIT_SUCCESS;
  690. }