videobuffer.c
来自「从 IEEE 1394总线接收传输流」· C语言 代码 · 共 362 行
C
362 行
/* * MPEG2-TS over IEEE 1394 decoder - receive and decode MPEG-2 transport * streams according to IEC 61883-4 * * Copyright (C) 2000-2007, Manfred Weihs <mweihs@users.sourceforge.net> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdlib.h>#include <stdio.h>#include <string.h>#include "videobuffer.h"#include <inttypes.h>#include <pthread.h>#include <time.h>#include <mpeg2.h>#include "video_out.h"#include "synchronisation.h"#include "config.h"#ifdef VIDEO_FIX_WINDOWextern void clear_tv_window();#endifextern int debug;struct videobuffer_entry videobuffer[VIDEOPESPACKETSINBUFFER];volatile int videobufferstart; /* points to the entry which the consumer currently consumes */volatile int videobufferend; /* points to the entry which the producer currently fills */sem_t videobuffer_sem;static pthread_t video_decoder_thread;static volatile int terminate_decoder;static int havedts;static unsigned long long int dts;static mpeg2dec_t * mpeg2dec;static vo_instance_t * output;static void process_picture_startcode() { if (havedts && is_sync_enabled()) fprintf(stderr,"warning: getting new video dts before using the last one!\n"); dts=videobuffer[videobufferstart].dts; havedts=videobuffer[videobufferstart].havedts; videobuffer[videobufferstart].havedts=0;}static int wait_for_pts() { struct timespec req; if (is_sync_enabled()) { if (havedts) { long long stc = getSTC(); long long int deviation=(long long int) dts - stc; /* how long shall we delay this frame */ /* compensate overflow in pcr or dts */ /* bring difference into the interval [-4294967296;4294967295] */ if (deviation < -4294967296ll) /* is in [-8589934591;-4294967297] */ deviation +=8589934592ll; else if (deviation > 4294967295ll) /* is in [4294967296;8589934591] */ deviation -= 8589934592ll; havedts=0; if (deviation < (-90000/25)) { /* we are more than 1/25 s late */ fprintf(stderr,"Video frame dropped, because it is too late\n"); return 0; } if (deviation > (90000*3)) { /* more than 3 second too early */ fprintf(stderr,"Video frame more than 3 seconds too early, it seems we lost synchronisation.\n"); return 1; } if (deviation < 0) { if (debug) { fprintf(stdout,"Video needs no sleep, because we are already a %lld ms late\n", deviation/90); } return 1; } req.tv_sec = deviation / 90000; req.tv_nsec = (deviation % 90000) * 100000 / 9; if (nanosleep(&req, NULL)) { fprintf(stderr,"sleep before displaying video frame was too short\n"); } return 1; } else { fprintf(stderr,"warning: we have no pts for this video frame -> displaying it immediately.\n"); } } return 1;}static void* video_decoder_thread_function(void *arg){ while (1) { if (sem_wait(&videobuffer_sem)) { fprintf(stderr,"Cannot P semaphore\n"); exit(0); } if (terminate_decoder) { return NULL; /* I think, that is cleaner than pthread_exit(0) */ } if ((videobufferstart +1) % VIDEOPESPACKETSINBUFFER == videobufferend) /* this may not happen because of semaphore */ { fprintf(stderr,"no frame in video buffer, stopped\n"); exit(0); } else { int old_havedts=videobuffer[videobufferstart].havedts; /* store value of dts of the old packet */ unsigned long long int old_dts=videobuffer[videobufferstart].dts; const mpeg2_info_t * info; int state; vo_setup_result_t setup_result; videobufferstart = (videobufferstart+1) % VIDEOPESPACKETSINBUFFER; /* advance buffer */ if (videobuffer[videobufferstart].continuation) /* if this is not a new PES packet */ { /* continue using old value of dts */ videobuffer[videobufferstart].dts=old_dts; videobuffer[videobufferstart].havedts=old_havedts; } else { if (old_havedts) fprintf(stderr,"warning: DTS of video packet dropped unused\n"); } mpeg2_buffer(mpeg2dec, videobuffer[videobufferstart].buffer, videobuffer[videobufferstart].buffer+videobuffer[videobufferstart].length); info = mpeg2_info(mpeg2dec); do { state = mpeg2_parse (mpeg2dec); switch (state) { case STATE_BUFFER: break; case STATE_SEQUENCE: /* might set nb fbuf, convert format, stride */ /* might set fbufs */ if (output->setup (output, info->sequence->width, info->sequence->height, info->sequence->chroma_width, info->sequence->chroma_height, &setup_result)) { fprintf (stderr, "display setup failed\n"); exit (1); } if (setup_result.convert && mpeg2_convert (mpeg2dec, setup_result.convert, NULL)) { fprintf (stderr, "color conversion setup failed\n"); exit (1); } if (output->set_fbuf) { uint8_t * buf[3]; void * id; mpeg2_custom_fbuf (mpeg2dec, 1); output->set_fbuf (output, buf, &id); mpeg2_set_buf (mpeg2dec, buf, id); output->set_fbuf (output, buf, &id); mpeg2_set_buf (mpeg2dec, buf, id); } else if (output->setup_fbuf) { uint8_t * buf[3]; void * id; output->setup_fbuf (output, buf, &id); mpeg2_set_buf (mpeg2dec, buf, id); output->setup_fbuf (output, buf, &id); mpeg2_set_buf (mpeg2dec, buf, id); output->setup_fbuf (output, buf, &id); mpeg2_set_buf (mpeg2dec, buf, id); } break; case STATE_PICTURE: process_picture_startcode(); // I am not sure, whether that is really correct here... //MAYBE call mpeg2_skip to skip, if we are already late here. /* might skip */ /* might set fbuf */ if (output->set_fbuf) { uint8_t * buf[3]; void * id; output->set_fbuf (output, buf, &id); mpeg2_set_buf (mpeg2dec, buf, id); } if (output->start_fbuf) { if (info->current_fbuf) { output->start_fbuf (output, info->current_fbuf->buf, info->current_fbuf->id); } else { fprintf(stderr,"warning: current_fbuf is NULL, maybe bug in libmpeg2\n"); } } break; case STATE_SLICE: case STATE_END: case STATE_INVALID_END: if (wait_for_pts()) { /* draw current picture */ if (info->display_fbuf) { if (output->draw) output->draw (output, info->display_fbuf->buf, info->display_fbuf->id); } } /* might free frame buffer */ if (output->discard && info->discard_fbuf) output->discard (output, info->discard_fbuf->buf, info->discard_fbuf->id); break; } } while (state != STATE_BUFFER); if (videobuffer[videobufferstart].flags & VIDEOBUFFER_FLAGS_CLEARSCREEN) { /* we shall clear the screen */ //FIXME: For now we only clear the fix window. It would, however, be better //to add a clearscreen method to vo_instance_t#ifdef VIDEO_FIX_WINDOW clear_tv_window();#endif } } } return 0; /* will never be reached */}#ifdef VIDEO_FIX_WINDOWstatic char vo_driver[100] = "xv fix";#elsestatic char vo_driver[100] = "xv";#endifvoid print_vo_drivers() { int i; vo_driver_t const * drivers; drivers = vo_drivers(); fprintf(stdout, "available video out drivers:\n"); for (i = 0; drivers[i].name; i++) { fprintf(stdout, " %s\n", drivers[i].name); } fprintf(stdout, "currently selected video out driver: %s\n", vo_driver);}void set_vo_driver(const char* driver_name) { strncpy(vo_driver, driver_name, sizeof(vo_driver));}int video_system_init(){ vo_open_t * output_open = NULL; vo_driver_t const * drivers; int i; drivers = vo_drivers (); for (i = 0; drivers[i].name != NULL; i++) { if (strcmp (drivers[i].name, vo_driver) == 0) { output_open = drivers[i].open; } } if (output_open == NULL) { fprintf (stderr, "video out driver %s not found\n", vo_driver); if (drivers[0].name != NULL) { fprintf (stderr, "using driver %s instead\n", drivers[0].name); output_open = drivers[0].open; } } if (output_open == NULL) { fprintf(stderr,"no valid output driver found\n"); exit(1); } output = output_open(); if (output == NULL) { fprintf(stderr,"Cannot open output\n"); exit(1); } mpeg2dec = mpeg2_init(); videobufferstart=0; videobufferend=1; havedts=0; videobuffer[videobufferend].length=0; videobuffer[videobufferend].havedts=0; videobuffer[videobufferend].flags=0; terminate_decoder=0; if (sem_init(&videobuffer_sem,0,0)) { fprintf(stderr,"Cannot create video semaphore\n"); exit(1); } if (pthread_create(&video_decoder_thread,NULL,video_decoder_thread_function,0)) { fprintf(stderr,"Cannot create video decoder thread\n"); exit(1); } return 1;}int video_system_done(){ void *result; terminate_decoder=1; if (sem_post(&videobuffer_sem)) /* we do this to ensure that the thread is activated */ { fprintf(stderr,"Cannot V semaphore\n"); exit(0); } if (pthread_join(video_decoder_thread,&result)) /* wait for thread to exit */ { fprintf(stderr,"Cannot join video decoder thread\n"); exit(1); } mpeg2_close(mpeg2dec); if (output->close) { output->close(output); } fprintf(stdout,"Video decoder terminated\n");fflush(stdout); if (sem_destroy(&videobuffer_sem)) { fprintf(stderr,"Cannot destroy video semaphore\n"); exit(1); } return 1;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?