/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * plsyer.cc * * Wed Nov 3 21:23:14 CET 2004 * Copyright 2004 Bent Bisballe * deva@aasimon.org ****************************************************************************/ /* * Originally from: * RTVideoRec Realtime video recoder and encoder for Linux * * Copyright (C) 2004 B. Stultiens * Copyright (C) 2004 Koen Otter and Glenn van der Meyden */ /* * This file is part of MIaV. * * MIaV is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MIaV is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MIaV; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "player.h" // Use libdv #include #include #include // For sleep #include Player::Player(Info *ginfo, int w, int h, volatile int *grunning, sem_t *gsem, Queue *gqueue, pthread_mutex_t *gmutex) { // No errors has ocurred... yet! noErrors = true; yuv_draw = new YUVDraw(); width = w; height = h; info = ginfo; running = grunning; sem = gsem; queue = gqueue; mutex = gmutex; sem_init(&play_sem, 0, 1); initSDL(); bypass = false; // Do not show the text showtext = false; recording = false; recording_prev = !recording; cprchanged = false; muted = false; muted_prev = !muted; } Player::~Player() { deinitSDL(); if(yuv_draw) delete yuv_draw; } void Player::reinitSDL() { deinitSDL(); initSDL(); } void Player::deinitSDL() { SDL_FreeYUVOverlay(overlay); SDL_Quit(); } void Player::initSDL() { if(SDL_Init(SDL_INIT_VIDEO) < 0) { info->error("Unable to init SDL: %s.", SDL_GetError()); noErrors = false; printf("failed!\n"); return; } screen = SDL_SetVideoMode(width, height, 0, // 0 bpp means 'use current display depth' SDL_HWSURFACE | SDL_ANYFORMAT | SDL_HWACCEL ); if(!screen) { info->error("Unable to set %dx%d video: %s.", 720, 576, SDL_GetError()); noErrors = false; printf("failed!\n"); return; } overlay = SDL_CreateYUVOverlay(720, 576, SDL_YUY2_OVERLAY, // Match for the libdv decoder output screen); if(!overlay) { info->error("Unable to create SDL overlay: %s.", SDL_GetError()); noErrors = false; printf("failed!\n"); return; } // Setup the displayarea. rect.x = 0; rect.y = 0; rect.w = width; rect.h = height; yuv_draw->setOverlay(overlay); } void Player::player() { SDL_Event event; Frame *frame; int pitches[3]; if(!noErrors) return; // FIXME: Gracefully exit... bool first = true; dv_decoder_t *decoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE); decoder->quality = DV_QUALITY_BEST; while(*running) { // Wait for the semaphore to be free... then run sem_wait(&play_sem); sem_post(&play_sem); if(bypass) continue; if(!SDL_WaitEvent(&event)) break; // FIXME: Gracefully exit... switch(event.type) { case SDL_KEYDOWN: switch(event.key.keysym.sym) { case SDLK_q: case SDLK_ESCAPE: goto quitit; default: break; } break; case SDL_USEREVENT: frame = queue->pop(); if(!frame) break; if(first) { pitches[0] = overlay->pitches[0]; pitches[1] = overlay->pitches[1]; pitches[2] = overlay->pitches[2]; dv_parse_header(decoder, frame->data); //dv_parse_packs(decoder, frame->data); // Not needed anyway! decoder->system = e_dv_system_625_50; // PAL lines, PAL framerate decoder->sampling = e_dv_sample_422; // 4 bytes y, 2 bytes u, 2 bytes v decoder->std = e_dv_std_iec_61834; decoder->num_dif_seqs = 12; first = false; } if(SDL_LockYUVOverlay(overlay) == -1) info->error("SDL_LockYUVOverlay failed."); // libdv img decode to yuv dv_decode_full_frame(decoder, frame->data, e_dv_color_yuv, overlay->pixels, pitches); // Set status text // if(muted != muted_prev) { yuv_draw->mute(muted); // muted_prev = muted; // } if(recording != recording_prev) { if(recording) yuv_draw->setTopText(TEXT_RECORDING); else yuv_draw->setTopText(TEXT_STOPPED); recording_prev = recording; } // Draw overlaytext (if enabled) if(showtext) { if(cprchanged) { yuv_draw->setBottomText(cpr); cprchanged = false; } yuv_draw->draw(); } SDL_UnlockYUVOverlay(overlay); SDL_DisplayYUVOverlay(overlay, &rect); delete frame; break; case SDL_QUIT: quitit: *running = 0; break; default: break; } } if(decoder) dv_decoder_free(decoder); struct timespec ts; /* Remove any late buffer */ /* We don't care, the encoder finishes them all */ ts.tv_sec = 0; ts.tv_nsec = 100000000L; // 100ms nanosleep(&ts, NULL); frame = queue->pop(); if(frame) delete frame; } void Player::thread_main() { player(); fprintf(stderr, "Player thread stopped.\n"); fflush(stderr); } void Player::start() { sem_post(&play_sem); } void Player::stop() { sem_wait(&play_sem); } // FIXME: Worst case genario: the loop takes more than 1 second // to stop displaying => crash, due to deinitialization // of SDL, while calling it.! void Player::resize(int w, int h, bool s) { // Tell loop to stop bypass = true; // Wait to ensure the current frame is done being displayed sleep(1); // Deinitialize SDL deinitSDL(); // Set new size width = w; height = h; // Initialize SDL initSDL(); // Tell loop to go on. bypass = false; showtext = s; } void Player::setCpr(char *newcpr, char* name) { sprintf(cpr, "ID: %s - %s", newcpr, name); cprchanged = true; } void Player::startrecord() { recording = true; } void Player::stoprecord() { recording = false; } void Player::setMute(bool m) { muted = m; }