player_example.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /*Daala video codec
  2. Copyright (c) 2006-2013 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. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <daala/codec.h>
  26. #include <daala/daaladec.h>
  27. #include "SDL.h"
  28. #define ODS_NONE 0
  29. #define ODS_HEADER 1
  30. #define ODS_DATA 2
  31. typedef struct {
  32. SDL_Surface *screen;
  33. daala_info di;
  34. daala_comment dc;
  35. ogg_sync_state oy;
  36. FILE *input;
  37. const char *input_path;
  38. ogg_stream_state os;
  39. daala_dec_ctx *dctx;
  40. SDL_Surface *surf;
  41. od_img img;
  42. int width;
  43. int height;
  44. int done;
  45. int od_state;
  46. int paused;
  47. int restart;
  48. int slow;
  49. int loop;
  50. int step;
  51. int valid;
  52. } player_example;
  53. static void img_to_rgb(SDL_Surface *surf, const od_img *img);
  54. int player_example_init(player_example *player);
  55. player_example *player_example_create();
  56. int player_example_clear(player_example *player);
  57. int player_example_free(player_example *player);
  58. int player_example_reset(player_example *player);
  59. int player_example_play(player_example *player);
  60. int player_example_restart(player_example *player);
  61. int player_example_open(player_example *player, char *path);
  62. int player_example_daala_stream_init(player_example *player, int serial) {
  63. int ret;
  64. if (player == NULL) return -1;
  65. ret = ogg_stream_init(&player->os, serial);
  66. if (ret != 0) return -1;
  67. daala_info_init(&player->di);
  68. daala_comment_init(&player->dc);
  69. player->od_state = ODS_HEADER;
  70. return 0;
  71. }
  72. int player_example_daala_stream_clear(player_example *player) {
  73. if (player == NULL) return -1;
  74. daala_info_clear(&player->di);
  75. daala_comment_clear(&player->dc);
  76. if (player->dctx != NULL) {
  77. daala_decode_free(player->dctx);
  78. player->dctx = NULL;
  79. }
  80. ogg_stream_clear(&player->os);
  81. player->od_state = ODS_NONE;
  82. return 0;
  83. }
  84. int player_example_init(player_example *player) {
  85. if (player == NULL) return -1;
  86. player->screen = NULL;
  87. player->surf = NULL;
  88. player->width = 0;
  89. player->height = 0;
  90. player->paused = 0;
  91. player->restart = 0;
  92. player->slow = 0;
  93. player->loop = 0;
  94. player->done = 0;
  95. player->step = 0;
  96. player->valid = 0;
  97. player->od_state = ODS_NONE;
  98. return 0;
  99. }
  100. int player_example_clear(player_example *player) {
  101. if (player == NULL) return -1;
  102. memset(player, 0, sizeof(player_example));
  103. return 0;
  104. }
  105. player_example *player_example_create() {
  106. int ret;
  107. player_example *player;
  108. player = (player_example *)malloc(sizeof(player_example));
  109. if (player == NULL) return NULL;
  110. ret = player_example_init(player);
  111. if (ret != 0) {
  112. free(player);
  113. return NULL;
  114. }
  115. return player;
  116. }
  117. int player_example_free(player_example *player) {
  118. int ret;
  119. if (player == NULL) return -1;
  120. ret = player_example_clear(player);
  121. if (ret == 0) {
  122. free(player);
  123. return 0;
  124. }
  125. return -1;
  126. }
  127. int player_example_reset(player_example *player) {
  128. int ret;
  129. if (player == NULL) return -1;
  130. ret = player_example_clear(player);
  131. if (ret != 0) return -1;
  132. ret = player_example_init(player);
  133. if (ret != 0) return -1;
  134. return 0;
  135. }
  136. int player_example_open_input(player_example *player, const char *path) {
  137. if ((player == NULL) || ((path == NULL) || (path[0] == '\0'))) return -1;
  138. if ((path[0] == '-') && (path[1] == '\0')) {
  139. player->input = stdin;
  140. }
  141. else {
  142. player->input = fopen(path, "rb");
  143. }
  144. if (player->input == NULL) {
  145. player->input_path = "";
  146. return -1;
  147. }
  148. player->input_path = path;
  149. ogg_sync_init(&player->oy);
  150. return 0;
  151. }
  152. int player_example_close_input(player_example *player) {
  153. int ret;
  154. if (player == NULL) return -1;
  155. if ((player->input == stdin) || (player->input == NULL)) return -1;
  156. ret = fclose(player->input);
  157. player->input = NULL;
  158. ogg_sync_clear(&player->oy);
  159. if (ret != 0) return -1;
  160. return 0;
  161. }
  162. int player_example_input_restart(player_example *player) {
  163. int ret;
  164. if (player == NULL) return -1;
  165. if (player->input == stdin) return -1;
  166. ret = player_example_close_input(player);
  167. if (ret != 0) return -1;
  168. ret = player_example_open_input(player, player->input_path);
  169. return ret;
  170. }
  171. void player_example_handle_event(player_example *player, SDL_Event *event) {
  172. switch (event->type) {
  173. case SDL_QUIT: {
  174. player->done = 1;
  175. break;
  176. }
  177. case SDL_KEYDOWN: {
  178. switch (event->key.keysym.sym) {
  179. case SDLK_q: {
  180. player->done = 1;
  181. break;
  182. }
  183. case SDLK_s: {
  184. player->slow = !player->slow;
  185. break;
  186. }
  187. case SDLK_l: {
  188. player->loop = !player->loop;
  189. break;
  190. }
  191. case SDLK_ESCAPE: {
  192. player->done = 1;
  193. break;
  194. }
  195. case SDLK_SPACE: {
  196. player->paused = !player->paused;
  197. player->step = 0;
  198. break;
  199. }
  200. case SDLK_PERIOD: {
  201. player->step = 1;
  202. player->paused = 1;
  203. break;
  204. }
  205. case SDLK_r: {
  206. player->restart = 1;
  207. if (player->paused) {
  208. player->step = 1;
  209. }
  210. break;
  211. }
  212. default: break;
  213. }
  214. break;
  215. }
  216. }
  217. }
  218. void player_example_wait_user_input(player_example *player) {
  219. SDL_Event event;
  220. if (SDL_WaitEvent(&event)) {
  221. player_example_handle_event(player, &event);
  222. }
  223. }
  224. void player_example_check_user_input(player_example *player) {
  225. SDL_Event event;
  226. while (SDL_PollEvent(&event)) {
  227. player_example_handle_event(player, &event);
  228. }
  229. }
  230. int player_example_play(player_example *player) {
  231. size_t bytes;
  232. char *buffer;
  233. int ret;
  234. ogg_page page;
  235. ogg_packet packet;
  236. daala_setup_info *dsi;
  237. dsi = NULL;
  238. while (!player->done) {
  239. while (ogg_sync_pageout(&player->oy, &page) != 1) {
  240. buffer = ogg_sync_buffer(&player->oy, 4096);
  241. if (buffer == NULL) return -1;
  242. bytes = fread(buffer, 1, 4096, player->input);
  243. if (bytes > 0) {
  244. ret = ogg_sync_wrote(&player->oy, bytes);
  245. if (ret != 0) return -1;
  246. }
  247. else {
  248. if (!player->valid) {
  249. fprintf(stderr, "Invalid Ogg\n");
  250. exit(1);
  251. }
  252. if (player->od_state != ODS_NONE) {
  253. ret = player_example_daala_stream_clear(player);
  254. if (ret != 0) return -1;
  255. }
  256. if (player->input == stdin) {
  257. return 0;
  258. }
  259. if (player->loop == 1) {
  260. player_example_input_restart(player);
  261. continue;
  262. }
  263. for (;;) {
  264. player_example_wait_user_input(player);
  265. if (player->restart) {
  266. ret = player_example_input_restart(player);
  267. player->restart = 0;
  268. if (ret != 0) return -1;
  269. break;
  270. }
  271. if (player->done) {
  272. return 0;
  273. }
  274. }
  275. }
  276. }
  277. if (ogg_page_bos(&page)) {
  278. ret = player_example_daala_stream_init(player,
  279. ogg_page_serialno(&page));
  280. if (ret != 0) return -1;
  281. }
  282. ret = ogg_stream_pagein(&player->os, &page);
  283. if (ret != 0) return -1;
  284. while (ogg_stream_packetout(&player->os, &packet) == 1) {
  285. switch (player->od_state) {
  286. case ODS_HEADER: {
  287. ret =
  288. daala_decode_header_in(&player->di, &player->dc, &dsi, &packet);
  289. if (ret < 0) {
  290. if (memcmp(packet.packet, "fishead", packet.bytes)) {
  291. fprintf(stderr, "Ogg Skeleton streams not supported\n");
  292. }
  293. return -1;
  294. }
  295. if (ret != 0) break;
  296. player->dctx = daala_decode_alloc(&player->di, dsi);
  297. if (player->dctx == NULL) return -1;
  298. daala_setup_free(dsi);
  299. dsi = NULL;
  300. player->od_state = ODS_DATA;
  301. /* Falling through */
  302. }
  303. case ODS_DATA: {
  304. if ((player->screen == NULL)
  305. || (player->width != player->di.pic_width)
  306. || (player->height != player->di.pic_height)) {
  307. player->width = player->di.pic_width;
  308. player->height = player->di.pic_height;
  309. player->screen = SDL_SetVideoMode(player->width, player->height,
  310. 24,
  311. SDL_HWSURFACE | SDL_DOUBLEBUF);
  312. if (player->screen == NULL) return -1;
  313. player->surf = SDL_GetVideoSurface();
  314. if (player->surf == NULL) return -1;
  315. }
  316. ret = daala_decode_packet_in(player->dctx, &player->img, &packet);
  317. if (ret != 0) return -1;
  318. player->valid = 1;
  319. if ((player->slow) && (!player->step)) {
  320. SDL_Delay(420);
  321. }
  322. player_example_check_user_input(player);
  323. while ((player->paused) && (!player->done)) {
  324. if (player->restart) {
  325. break;
  326. }
  327. if (player->step) {
  328. player->step = 0;
  329. break;
  330. }
  331. player_example_wait_user_input(player);
  332. }
  333. if ((!player->restart) && (!player->done)) {
  334. SDL_LockSurface(player->surf);
  335. img_to_rgb(player->surf, &player->img);
  336. SDL_UnlockSurface(player->surf);
  337. SDL_Flip(player->screen);
  338. }
  339. break;
  340. }
  341. }
  342. }
  343. if ((player->restart) || (ogg_page_eos(&page))) {
  344. ret = player_example_daala_stream_clear(player);
  345. if (ret != 0) return -1;
  346. }
  347. if (player->restart) {
  348. ret = player_example_input_restart(player);
  349. player->restart = 0;
  350. if (ret != 0) return -1;
  351. }
  352. }
  353. if (player->od_state != ODS_NONE) {
  354. ret = player_example_daala_stream_clear(player);
  355. if (ret != 0) return -1;
  356. }
  357. return 0;
  358. }
  359. int main(int argc, char *argv[]) {
  360. int ret;
  361. char *input;
  362. int start_paused;
  363. player_example *player;
  364. daala_log_init();
  365. if ((argc == 3) && (memcmp(argv[1], "-p", 2) == 0)) {
  366. start_paused = 1;
  367. input = argv[2];
  368. }
  369. else {
  370. if ((argc != 2) || ((argc == 2)
  371. && ((memcmp(argv[1], "-h", 2) == 0)
  372. || (memcmp(argv[1] + 1, "-h", 2) == 0)))) {
  373. fprintf(stderr, "usage: %s input.ogg\n%s\n", argv[0],
  374. "\nProgram Options:\n-p to start paused\n- to read from stdin\n\n"
  375. "Playback Control: \n"
  376. "r to restart\nl to loop\ns for slow\n. to step\nspace to pause\n"
  377. "q to quit");
  378. exit(1);
  379. }
  380. start_paused = 0;
  381. input = argv[1];
  382. }
  383. if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  384. fprintf(stderr, "error: unable to init SDL\n");
  385. exit(1);
  386. }
  387. atexit(SDL_Quit);
  388. SDL_EnableKeyRepeat(222, 100);
  389. player = player_example_create();
  390. if (player == NULL) {
  391. fprintf(stderr, "player example error: create player\n");
  392. return -1;
  393. }
  394. ret = player_example_open_input(player, input);
  395. if (ret != 0) {
  396. fprintf(stderr, "player example error: could not open: %s\n", input);
  397. player_example_free(player);
  398. return -1;
  399. }
  400. if (start_paused == 1) {
  401. player->step = 1;
  402. player->paused = 1;
  403. }
  404. ret = player_example_play(player);
  405. if (ret != 0) {
  406. fprintf(stderr, "player example error: playback error\n");
  407. exit(1);
  408. }
  409. ret = player_example_free(player);
  410. return ret;
  411. }
  412. #define OD_MINI(a, b) ((a) < (b) ? (a) : (b))
  413. #define OD_MAXI(a, b) ((a) > (b) ? (a) : (b))
  414. #define OD_CLAMPI(a, b, c) (OD_MAXI(a, OD_MINI(b, c)))
  415. #define OD_SIGNMASK(a) (-((a) < 0))
  416. #define OD_FLIPSIGNI(a, b) (((a) + OD_SIGNMASK(b)) ^ OD_SIGNMASK(b))
  417. #define OD_DIV_ROUND(x, y) (((x) + OD_FLIPSIGNI((y) >> 1, x))/(y))
  418. #define OD_CLAMP255(x) \
  419. ((unsigned char)((((x) < 0) - 1) & ((x) | -((x) > 255))))
  420. void img_to_rgb(SDL_Surface *surf, const od_img *img) {
  421. unsigned char *y_row;
  422. unsigned char *cb_row;
  423. unsigned char *cr_row;
  424. unsigned char *y;
  425. unsigned char *cb;
  426. unsigned char *cr;
  427. int y_stride;
  428. int cb_stride;
  429. int cr_stride;
  430. int width;
  431. int height;
  432. int xdec;
  433. int ydec;
  434. int i;
  435. int j;
  436. unsigned char *pixels;
  437. int pitch;
  438. pixels = (unsigned char *)surf->pixels;
  439. pitch = surf->pitch;
  440. width = img->width;
  441. height = img->height;
  442. /*Assume both C planes are decimated.*/
  443. xdec = img->planes[1].xdec;
  444. ydec = img->planes[1].ydec;
  445. y_stride = img->planes[0].ystride;
  446. cb_stride = img->planes[1].ystride;
  447. cr_stride = img->planes[2].ystride;
  448. y_row = img->planes[0].data;
  449. cb_row = img->planes[1].data;
  450. cr_row = img->planes[2].data;
  451. /*Chroma up-sampling is just done with a box filter.
  452. This is very likely what will actually be used in practice on a real
  453. display, and also removes one more layer to search in for the source of
  454. artifacts.
  455. As an added bonus, it's dead simple.*/
  456. for (j = 0; j < height; j++) {
  457. int dc;
  458. y = y_row;
  459. cb = cb_row;
  460. cr = cr_row;
  461. for (i = 0; i < 3 * width;) {
  462. int64_t yval;
  463. int64_t cbval;
  464. int64_t crval;
  465. unsigned rval;
  466. unsigned gval;
  467. unsigned bval;
  468. yval = *y - 16;
  469. cbval = *cb - 128;
  470. crval = *cr - 128;
  471. /*This is intentionally slow and very accurate.*/
  472. rval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
  473. 2916394880000LL*yval + 4490222169144LL*crval, 9745792000LL), 65535);
  474. gval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
  475. 2916394880000LL*yval - 534117096223LL*cbval - 1334761232047LL*crval,
  476. 9745792000LL), 65535);
  477. bval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
  478. 2916394880000LL*yval + 5290866304968LL*cbval, 9745792000LL), 65535);
  479. *(pixels + pitch*j + i++) = (unsigned char)(bval >> 8);
  480. *(pixels + pitch*j + i++) = (unsigned char)(gval >> 8);
  481. *(pixels + pitch*j + i++) = (unsigned char)(rval >> 8);
  482. dc = ((y - y_row) & 1) | (1 - xdec);
  483. y++;
  484. cb += dc;
  485. cr += dc;
  486. }
  487. y_row += y_stride;
  488. dc = -((j & 1) | (1 - ydec));
  489. cb_row += dc & cb_stride;
  490. cr_row += dc & cr_stride;
  491. }
  492. }