/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * decoder.cc * * Sat Feb 19 17:05:43 CET 2005 * Copyright 2005 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 "decoder.h" #include // Use libdv #include #include #include #include "frame_stream.h" #include "miav_config.h" #include "dv.h" #include "dvfile.h" #include "dv1394.h" Decoder::Decoder(Info *ginfo, sem_t *gencode_sem, sem_t *gplayer_sem, Queue *gencode_queue, Queue *gplayer_queue, pthread_mutex_t *gmutex, volatile int *grunning) { info = ginfo; encode_sem = gencode_sem; player_sem = gplayer_sem; encode_queue = gencode_queue; player_queue = gplayer_queue; mutex = gmutex; running = grunning; b_shoot = false; b_freeze = false; b_record = false; // Initially no recording is done. pthread_mutex_init (&shot_mutex, NULL); shot = NULL; mute = false; } Decoder::~Decoder() { pthread_mutex_destroy(&shot_mutex); } void Decoder::decode() { frame_stream *dvstream; bool local_shoot; int local_freeze; bool local_record = false; bool old_record; bool skip_frames = config->readInt("player_skip_frames"); dv1394 dv1394_stream(info); // Use default port and channel. dvfile dvfile_stream(info); if(dv1394_stream.connect()) { // Use the dv1394 stream for input. dvstream = &dv1394_stream; } else { // Use the fallback dv filereader for input. dvstream = &dvfile_stream; } while(*running) { uint8_t *ptr; SDL_Event user_event; // Read a dvframe ptr = dvstream->readFrame(); if(!ptr) return; // No frame read. (Due to dv read error) old_record = local_record; local_shoot = b_shoot; b_shoot = false; local_freeze = b_freeze; b_freeze = false; local_record = b_record; if(local_shoot) { pthread_mutex_lock(&shot_mutex); if(!shot) shot = new Frame(ptr, DVPACKAGE_SIZE); pthread_mutex_unlock(&shot_mutex); } if(local_freeze == 1) { pthread_mutex_lock(&shot_mutex); if(shot) delete shot; shot = new Frame(ptr, DVPACKAGE_SIZE); pthread_mutex_unlock(&shot_mutex); } static int showframe = 1; if(skip_frames != 0) showframe = 1 - showframe; if(showframe) { Frame *pframe = new Frame(ptr, DVPACKAGE_SIZE); pframe->shoot = local_shoot; pframe->freeze = local_freeze; pframe->record = local_record; player_queue->push(pframe); // Create and send SDL event. user_event.type = SDL_USEREVENT; user_event.user.code = 0; user_event.user.data1 = NULL; user_event.user.data2 = NULL; SDL_PushEvent(&user_event); } if(local_record | (local_record != old_record) | local_shoot | local_freeze) { Frame *eframe = new Frame(NULL, 0); eframe->data = ptr; eframe->size = DVPACKAGE_SIZE; eframe->shoot = local_shoot; eframe->freeze = local_freeze; eframe->record = local_record; eframe->mute = mute; encode_queue->push(eframe); sem_post(encode_sem); } else { free(ptr); } } // Kick the others so they wake up with empty queues sem_post(encode_sem); } void Decoder::thread_main() { decode(); fprintf(stderr, "Decoder thread stopped.\n"); fflush(stderr); } /* * Set freeze bit on current frame. */ void Decoder::freeze() { b_freeze = 1; } /* * Remove frozen frame. */ void Decoder::unfreeze() { b_freeze = -1; pthread_mutex_lock(&shot_mutex); delete shot; shot = NULL; pthread_mutex_unlock(&shot_mutex); } /* * Set shoot bit on current frame. */ void Decoder::shoot(unsigned char *rgb) { struct timespec ts; b_shoot = true; // Wait for shot to be taken while(1) { pthread_mutex_lock(&shot_mutex); if(shot) { getScreenshot(shot, rgb); delete shot; shot = NULL; pthread_mutex_unlock(&shot_mutex); return; } pthread_mutex_unlock(&shot_mutex); ts.tv_sec = 0; ts.tv_nsec = 100000000L; // 100ms nanosleep(&ts, NULL); } } /* * Set the record bit to true in all following frames. */ void Decoder::start() { b_record = true; } /* * Set the record bit to false in all following frames. */ void Decoder::stop(n_savestate save) { b_record = false; } void Decoder::getScreenshot(Frame *frame, unsigned char *rgb) { unsigned char *pixels[3]; int pitches[3]; pixels[ 0 ] = rgb; pixels[ 1 ] = NULL; pixels[ 2 ] = NULL; pitches[ 0 ] = 720 * 4; pitches[ 1 ] = 0; pitches[ 2 ] = 0; dv_decoder_t *decoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE); decoder->quality = DV_QUALITY_BEST; dv_parse_header(decoder, frame->data); 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; // libdv img decode to rgb dv_decode_full_frame(decoder, frame->data, e_dv_color_bgr0, pixels, pitches); dv_decoder_free(decoder); } void Decoder::setMute(bool m) { mute = m; }