123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- /*Daala video codec
- Copyright (c) 2006-2013 Daala project contributors. All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- - Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
- #ifdef HAVE_CONFIG_H
- # include "config.h"
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <daala/codec.h>
- #include <daala/daaladec.h>
- #include "SDL.h"
- #define ODS_NONE 0
- #define ODS_HEADER 1
- #define ODS_DATA 2
- typedef struct {
- SDL_Window *screen;
- SDL_Renderer *renderer;
- daala_info di;
- daala_comment dc;
- ogg_sync_state oy;
- FILE *input;
- const char *input_path;
- ogg_stream_state os;
- daala_dec_ctx *dctx;
- SDL_Texture *texture;
- od_img img;
- int width;
- int height;
- int done;
- int od_state;
- int paused;
- int restart;
- int slow;
- int loop;
- int step;
- int fullscreen;
- int valid;
- int plane_mask;
- } player_example;
- enum {
- OD_LUMA_MASK = 1 << 0,
- OD_CB_MASK = 1 << 1,
- OD_CR_MASK = 1 << 2,
- OD_ALL_MASK = OD_LUMA_MASK | OD_CB_MASK | OD_CR_MASK
- };
- static void img_to_rgb(SDL_Texture *tex, const od_img *img, int plane_mask);
- static int next_plane(int plane_mask);
- static void wait_to_refresh(uint32_t *previous_ticks, uint32_t ms_per_frame);
- int player_example_init(player_example *player);
- player_example *player_example_create();
- int player_example_clear(player_example *player);
- int player_example_free(player_example *player);
- int player_example_reset(player_example *player);
- int player_example_play(player_example *player);
- int player_example_restart(player_example *player);
- int player_example_open(player_example *player, char *path);
- int player_example_daala_stream_init(player_example *player, int serial) {
- int ret;
- if (player == NULL) return -1;
- ret = ogg_stream_init(&player->os, serial);
- if (ret != 0) return -1;
- daala_info_init(&player->di);
- daala_comment_init(&player->dc);
- player->od_state = ODS_HEADER;
- return 0;
- }
- int player_example_daala_stream_clear(player_example *player) {
- if (player == NULL) return -1;
- daala_info_clear(&player->di);
- daala_comment_clear(&player->dc);
- if (player->dctx != NULL) {
- daala_decode_free(player->dctx);
- player->dctx = NULL;
- }
- ogg_stream_clear(&player->os);
- player->od_state = ODS_NONE;
- return 0;
- }
- int player_example_init(player_example *player) {
- if (player == NULL) return -1;
- player->screen = NULL;
- player->renderer = NULL;
- player->texture = NULL;
- player->width = 0;
- player->height = 0;
- player->paused = 0;
- player->restart = 0;
- player->slow = 0;
- player->loop = 0;
- player->done = 0;
- player->step = 0;
- player->fullscreen = 0;
- player->valid = 0;
- player->od_state = ODS_NONE;
- player->plane_mask = OD_ALL_MASK;
- return 0;
- }
- int player_example_clear(player_example *player) {
- if (player == NULL) return -1;
- memset(player, 0, sizeof(player_example));
- return 0;
- }
- player_example *player_example_create() {
- int ret;
- player_example *player;
- player = (player_example *)malloc(sizeof(player_example));
- if (player == NULL) return NULL;
- ret = player_example_init(player);
- if (ret != 0) {
- free(player);
- return NULL;
- }
- return player;
- }
- int player_example_free(player_example *player) {
- int ret;
- if (player == NULL) return -1;
- ret = player_example_clear(player);
- if (ret == 0) {
- free(player);
- return 0;
- }
- return -1;
- }
- int player_example_reset(player_example *player) {
- int ret;
- if (player == NULL) return -1;
- ret = player_example_clear(player);
- if (ret != 0) return -1;
- ret = player_example_init(player);
- if (ret != 0) return -1;
- return 0;
- }
- int player_example_open_input(player_example *player, const char *path) {
- if ((player == NULL) || ((path == NULL) || (path[0] == '\0'))) return -1;
- if ((path[0] == '-') && (path[1] == '\0')) {
- player->input = stdin;
- }
- else {
- player->input = fopen(path, "rb");
- }
- if (player->input == NULL) {
- player->input_path = "";
- return -1;
- }
- player->input_path = path;
- ogg_sync_init(&player->oy);
- return 0;
- }
- int player_example_close_input(player_example *player) {
- int ret;
- if (player == NULL) return -1;
- if ((player->input == stdin) || (player->input == NULL)) return -1;
- ret = fclose(player->input);
- player->input = NULL;
- ogg_sync_clear(&player->oy);
- if (ret != 0) return -1;
- return 0;
- }
- int player_example_input_restart(player_example *player) {
- int ret;
- if (player == NULL) return -1;
- if (player->input == stdin) return -1;
- ret = player_example_close_input(player);
- if (ret != 0) return -1;
- ret = player_example_open_input(player, player->input_path);
- return ret;
- }
- void player_example_handle_event(player_example *player, SDL_Event *event) {
- switch (event->type) {
- case SDL_QUIT: {
- player->done = 1;
- break;
- }
- case SDL_KEYDOWN: {
- switch (event->key.keysym.sym) {
- case SDLK_q: {
- player->done = 1;
- break;
- }
- case SDLK_s: {
- player->slow = !player->slow;
- break;
- }
- case SDLK_p: {
- player->plane_mask = next_plane(player->plane_mask);
- break;
- }
- case SDLK_l: {
- player->loop = !player->loop;
- break;
- }
- case SDLK_ESCAPE: {
- player->done = 1;
- break;
- }
- case SDLK_SPACE: {
- player->paused = !player->paused;
- player->step = 0;
- break;
- }
- case SDLK_RIGHT:
- case SDLK_PERIOD: {
- player->step = 1;
- player->paused = 1;
- break;
- }
- case SDLK_HOME:
- case SDLK_r: {
- player->restart = 1;
- if (player->paused) {
- player->step = 1;
- }
- break;
- }
- case SDLK_f: {
- player->fullscreen = !player->fullscreen;
- SDL_SetWindowFullscreen(player->screen,
- player->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
- break;
- }
- default: break;
- }
- break;
- }
- }
- }
- void player_example_wait_user_input(player_example *player) {
- SDL_Event event;
- if (SDL_WaitEvent(&event)) {
- player_example_handle_event(player, &event);
- }
- }
- void player_example_check_user_input(player_example *player) {
- SDL_Event event;
- while (SDL_PollEvent(&event)) {
- player_example_handle_event(player, &event);
- }
- }
- int player_example_play(player_example *player) {
- size_t bytes;
- char *buffer;
- int ret;
- ogg_page page;
- ogg_packet packet;
- daala_setup_info *dsi;
- uint32_t ms_per_frame;
- uint32_t ticks = 0;
- ms_per_frame = 0;
- dsi = NULL;
- while (!player->done) {
- while (ogg_sync_pageout(&player->oy, &page) != 1) {
- buffer = ogg_sync_buffer(&player->oy, 4096);
- if (buffer == NULL) return -1;
- bytes = fread(buffer, 1, 4096, player->input);
- if (bytes > 0) {
- ret = ogg_sync_wrote(&player->oy, bytes);
- if (ret != 0) return -1;
- }
- else {
- if (!player->valid) {
- fprintf(stderr, "Invalid Ogg\n");
- exit(1);
- }
- if (player->od_state != ODS_NONE) {
- ret = player_example_daala_stream_clear(player);
- if (ret != 0) return -1;
- }
- if (player->input == stdin) {
- return 0;
- }
- if (player->loop == 1) {
- player_example_input_restart(player);
- continue;
- }
- for (;;) {
- player_example_wait_user_input(player);
- if (player->restart) {
- ret = player_example_input_restart(player);
- player->restart = 0;
- if (ret != 0) return -1;
- break;
- }
- if (player->done) {
- return 0;
- }
- }
- }
- }
- if (ogg_page_bos(&page)) {
- ret = player_example_daala_stream_init(player,
- ogg_page_serialno(&page));
- if (ret != 0) return -1;
- }
- ret = ogg_stream_pagein(&player->os, &page);
- if (ret != 0) return -1;
- while (ogg_stream_packetout(&player->os, &packet) == 1) {
- switch (player->od_state) {
- case ODS_HEADER: {
- ret =
- daala_decode_header_in(&player->di, &player->dc, &dsi, &packet);
- if (ret < 0) {
- if (memcmp(packet.packet, "fishead", packet.bytes)) {
- fprintf(stderr, "Ogg Skeleton streams not supported\n");
- }
- return -1;
- }
- if (ret != 0) break;
- player->dctx = daala_decode_alloc(&player->di, dsi);
- if (player->dctx == NULL) return -1;
- daala_setup_free(dsi);
- dsi = NULL;
- player->od_state = ODS_DATA;
- if (player->di.timebase_numerator
- && player->di.timebase_denominator) {
- ms_per_frame = 1000 /
- (player->di.timebase_numerator / player->di.timebase_denominator);
- ticks = SDL_GetTicks();
- }
- break;
- }
- case ODS_DATA: {
- if ((player->screen == NULL)
- || (player->width != player->di.pic_width)
- || (player->height != player->di.pic_height)) {
- player->width = player->di.pic_width;
- player->height = player->di.pic_height;
- player->screen = SDL_CreateWindow("Daala example player",
- SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
- player->width, player->height,
- SDL_WINDOW_ALLOW_HIGHDPI);
- if (player->screen == NULL) return -1;
- player->renderer = SDL_CreateRenderer(player->screen, -1, 0);
- if (player->renderer == NULL) return -1;
- player->texture = SDL_CreateTexture(player->renderer,
- SDL_PIXELFORMAT_ARGB8888,
- SDL_TEXTUREACCESS_STREAMING,
- player->width, player->height);
- if (player->texture == NULL) return -1;
- }
- ret = daala_decode_packet_in(player->dctx, &player->img, &packet);
- if (ret != 0) return -1;
- player->valid = 1;
- if ((player->slow) && (!player->step)) {
- SDL_Delay(420);
- }
- player_example_check_user_input(player);
- while ((player->paused) && (!player->done)) {
- if (player->restart) {
- break;
- }
- if (player->step) {
- player->step = 0;
- break;
- }
- player_example_wait_user_input(player);
- }
- if ((!player->restart) && (!player->done)) {
- wait_to_refresh(&ticks, ms_per_frame);
- img_to_rgb(player->texture, &player->img, player->plane_mask);
- SDL_RenderClear(player->renderer);
- SDL_RenderCopy(player->renderer, player->texture, NULL, NULL);
- SDL_RenderPresent(player->renderer);
- }
- break;
- }
- }
- }
- if ((player->restart) || (ogg_page_eos(&page))) {
- ret = player_example_daala_stream_clear(player);
- if (ret != 0) return -1;
- }
- if (player->restart) {
- ret = player_example_input_restart(player);
- player->restart = 0;
- if (ret != 0) return -1;
- }
- }
- if (player->od_state != ODS_NONE) {
- ret = player_example_daala_stream_clear(player);
- if (ret != 0) return -1;
- }
- return 0;
- }
- int main(int argc, char *argv[]) {
- int ret;
- char *input;
- int start_paused;
- player_example *player;
- daala_log_init();
- if ((argc == 3) && (memcmp(argv[1], "-p", 2) == 0)) {
- start_paused = 1;
- input = argv[2];
- }
- else {
- if ((argc != 2) || ((argc == 2)
- && ((memcmp(argv[1], "-h", 2) == 0)
- || (memcmp(argv[1] + 1, "-h", 2) == 0)))) {
- fprintf(stderr, "usage: %s input.ogg\n%s\n", argv[0],
- "\nProgram Options:\n-p to start paused\n- to read from stdin\n\n"
- "Playback Control: \n"
- "r to restart\nl to loop\ns for slow\n. to step\nspace to pause\n"
- "p to switch planes\nq to quit");
- exit(1);
- } else if ((argc == 2)
- && memcmp(argv[1], "--version", 9) == 0
- && strlen(argv[1]) == strlen("--version")) {
- fprintf(stderr, "%s\n", PACKAGE_STRING);
- exit(0);
- }
- start_paused = 0;
- input = argv[1];
- }
- if (SDL_Init(SDL_INIT_VIDEO) < 0) {
- fprintf(stderr, "error: unable to init SDL\n");
- exit(1);
- }
- atexit(SDL_Quit);
- player = player_example_create();
- if (player == NULL) {
- fprintf(stderr, "player example error: create player\n");
- return -1;
- }
- ret = player_example_open_input(player, input);
- if (ret != 0) {
- fprintf(stderr, "player example error: could not open: %s\n", input);
- player_example_free(player);
- return -1;
- }
- if (start_paused == 1) {
- player->step = 1;
- player->paused = 1;
- }
- ret = player_example_play(player);
- if (ret != 0) {
- fprintf(stderr, "player example error: playback error\n");
- exit(1);
- }
- ret = player_example_free(player);
- return ret;
- }
- #define OD_MINI(a, b) ((a) < (b) ? (a) : (b))
- #define OD_MAXI(a, b) ((a) > (b) ? (a) : (b))
- #define OD_CLAMPI(a, b, c) (OD_MAXI(a, OD_MINI(b, c)))
- #define OD_SIGNMASK(a) (-((a) < 0))
- #define OD_FLIPSIGNI(a, b) (((a) + OD_SIGNMASK(b)) ^ OD_SIGNMASK(b))
- #define OD_DIV_ROUND(x, y) (((x) + OD_FLIPSIGNI((y) >> 1, x))/(y))
- #define OD_CLAMP255(x) \
- ((unsigned char)((((x) < 0) - 1) & ((x) | -((x) > 255))))
- void img_to_rgb(SDL_Texture *texture, const od_img *img, int plane_mask) {
- unsigned char *y_row;
- unsigned char *cb_row;
- unsigned char *cr_row;
- unsigned char *y;
- unsigned char *cb;
- unsigned char *cr;
- int y_stride;
- int cb_stride;
- int cr_stride;
- int width;
- int height;
- int xdec;
- int ydec;
- int i;
- int j;
- unsigned char *pixels;
- int pitch;
- /*Assume both C planes are decimated.*/
- xdec = img->planes[1].xdec;
- ydec = img->planes[1].ydec;
- y_stride = img->planes[0].ystride;
- cb_stride = img->planes[1].ystride;
- cr_stride = img->planes[2].ystride;
- y_row = img->planes[0].data;
- cb_row = img->planes[1].data;
- cr_row = img->planes[2].data;
- /*Lock the texture in video memory for update.*/
- if (SDL_LockTexture(texture, NULL, (void**)&pixels, &pitch)) {
- fprintf(stderr, "Couldn't lock video texture!");
- exit(1);
- }
- width = img->width;
- height = img->height;
- /*Chroma up-sampling is just done with a box filter.
- This is very likely what will actually be used in practice on a real
- display, and also removes one more layer to search in for the source of
- artifacts.
- As an added bonus, it's dead simple.*/
- for (j = 0; j < height; j++) {
- int dc;
- y = y_row;
- cb = cb_row;
- cr = cr_row;
- for (i = 0; i < 4 * width;) {
- int64_t yval;
- int64_t cbval;
- int64_t crval;
- unsigned rval;
- unsigned gval;
- unsigned bval;
- yval = (plane_mask & OD_LUMA_MASK) * (*y - 16)
- + (((plane_mask & OD_LUMA_MASK) ^ OD_LUMA_MASK) << 7);
- cbval = ((plane_mask & OD_CB_MASK) >> 1) * (*cb - 128);
- crval = ((plane_mask & OD_CR_MASK) >> 2) * (*cr - 128);
- /*This is intentionally slow and very accurate.*/
- rval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
- 2916394880000LL*yval + 4490222169144LL*crval, 9745792000LL), 65535);
- gval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
- 2916394880000LL*yval - 534117096223LL*cbval - 1334761232047LL*crval,
- 9745792000LL), 65535);
- bval = OD_CLAMPI(0, (int32_t)OD_DIV_ROUND(
- 2916394880000LL*yval + 5290866304968LL*cbval, 9745792000LL), 65535);
- *(pixels + pitch*j + i++) = (unsigned char)(bval >> 8);
- *(pixels + pitch*j + i++) = (unsigned char)(gval >> 8);
- *(pixels + pitch*j + i++) = (unsigned char)(rval >> 8);
- *(pixels + pitch*j + i++) = 0;
- dc = ((y - y_row) & 1) | (1 - xdec);
- y++;
- cb += dc;
- cr += dc;
- }
- y_row += y_stride;
- dc = -((j & 1) | (1 - ydec));
- cb_row += dc & cb_stride;
- cr_row += dc & cr_stride;
- }
- SDL_UnlockTexture(texture);
- }
- int next_plane(int plane_mask) {
- return OD_MINI(plane_mask << 1, OD_ALL_MASK) >>
- ((plane_mask == OD_ALL_MASK) << 1);
- }
- void wait_to_refresh(uint32_t *previous_ticks, uint32_t ms_per_frame)
- {
- uint32_t tmp;
- /* play dumb until we've parsed the frame rate */
- if (!*previous_ticks)
- return;
- tmp = SDL_GetTicks();
- while (tmp - *previous_ticks < ms_per_frame) {
- SDL_Delay(ms_per_frame - (tmp - *previous_ticks));
- tmp = SDL_GetTicks();
- }
- *previous_ticks = tmp;
- }
|