liblavplay.c
来自「Motion JPEG编解码器源代码」· C语言 代码 · 共 2,022 行 · 第 1/5 页
C
2,022 行
/* * liblavplay - a librarified Linux Audio Video PLAYback * * Copyright (C) 2000 Rainer Johanni <Rainer@Johanni.de> * Extended by: Gernot Ziegler <gz@lysator.liu.se> * Ronald Bultje <rbultje@ronald.bitfreak.net> * & many others * * A library for playing back MJPEG video via software MJPEG * decompression (using SDL) or via hardware MJPEG video * devices such as the Pinnacle/Miro DC10(+), Iomega Buz, * the Linux Media Labs LML33, the Matrox Marvel G200, * Matrox Marvel G400 and the Rainbow Runner G-series. * * 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 <config.h>#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/wait.h>#ifdef HAVE_V4L#include <sys/vfs.h>#endif#ifndef X_DISPLAY_MISSING#include <X11/Xlib.h>#include <X11/Xutil.h>#endif#ifdef HAVE_SYS_SOUNDCARD_H#include <sys/soundcard.h>#endif#ifdef HAVE_V4L /* Because of some really cool feature in video4linux1, also known as * 'not including sys/types.h and sys/time.h', we had to include it * ourselves. In all their intelligence, these people decided to fix * this in the next version (video4linux2) in such a cool way that it * breaks all compilations of old stuff... * The real problem is actually that linux/time.h doesn't use proper * macro checks before defining types like struct timeval. The proper * fix here is to either fuck the kernel header (which is what we do * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it * upstream, which I'll consider doing later on. If you get compiler * errors here, check your linux/time.h && sys/time.h header setup. */#define _LINUX_TIME_H#include <linux/videodev.h>#else#define VIDEO_MODE_PAL 0#define VIDEO_MODE_NTSC 1#define VIDEO_MODE_SECAM 2#define VIDEO_MODE_AUTO 3#endif#include <videodev_mjpeg.h>#include <pthread.h>#ifdef HAVE_SDL#include <SDL/SDL.h>#endif#include "mjpeg_types.h"#include "liblavplay.h"#include "audiolib.h"/*#include "lav_io.h" *//*#include "editlist.h" */#include "jpegutils.h"#ifdef HAVE_LIBDV#include <libdv/dv.h>#endif/* Prototypes to avoid compile time warning errors */void frame_YUV422_to_YUV420P(uint8_t **, uint8_t *, int , int );#ifdef HAVE_SDLint frame_planar_to_packed(uint8_t *, uint8_t **, int, int, int, int, int);#endif/* * As far as I (maddog) can tell, this is what is going on with libdv-0.9 * and the unpacking routine... * o Ft/Fb refer to top/bottom scanlines (interleaved) --- each sample * is implicitly tagged by 't' or 'b' (samples are not mixed between * fields) * o Indices on Cb and Cr samples indicate the Y sample with which * they are co-sited. * o '^' indicates which samples are preserved by the unpacking * * libdv packs both NTSC 4:1:1 and PAL 4:2:0 into a common frame format of * packed 4:2:2 pixels as follows: * * ***** NTSC 4:1:1 ***** * * libdv's 4:2:2-packed representation (chroma repeated horizontally) * *Ft Y00.Cb00.Y01.Cr00.Y02.Cb00.Y03.Cr00 Y04.Cb04.Y05.Cr04.Y06.Cb04.Y07.Cr04 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ *Fb Y00.Cb00.Y01.Cr00.Y02.Cb00.Y03.Cr00 Y04.Cb04.Y05.Cr04.Y06.Cb04.Y07.Cr04 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ *Ft Y10.Cb10.Y11.Cr10.Y12.Cb10.Y13.Cr10 Y14.Cb14.Y15.Cr14.Y16.Cb14.Y17.Cr14 * ^ ^ ^ ^ ^ ^ ^ ^ *Fb Y10.Cb10.Y11.Cr10.Y12.Cb10.Y13.Cr10 Y14.Cb14.Y15.Cr14.Y16.Cb14.Y17.Cr14 * ^ ^ ^ ^ ^ ^ ^ ^ * * lavtools unpacking into 4:2:0-planar (note lossiness) * *Ft Y00.Y01.Y02.Y03.Y04.Y05.Y06.Y07... *Fb Y00.Y01.Y02.Y03.Y04.Y05.Y06.Y07... *Ft Y10.Y11.Y12.Y13.Y14.Y15.Y16.Y17... *Fb Y10.Y11.Y12.Y13.Y14.Y15.Y16.Y17... * *Ft Cb00.Cb00.Cb04.Cb04... Cb00,Cb04... are doubled *Fb Cb00.Cb00.Cb04.Cb04... Cb10,Cb14... are ignored * *Ft Cr00.Cr00.Cr04.Cr04... *Fb Cr00.Cr00.Cr04.Cr04... * * ***** PAL 4:2:0 ***** * * libdv's 4:2:2-packed representation (chroma repeated vertically) * *Ft Y00.Cb00.Y01.Cr10.Y02.Cb02.Y03.Cr12 Y04.Cb04.Y05.Cr14.Y06.Cb06.Y07.Cr16 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ *Fb Y00.Cb00.Y01.Cr10.Y02.Cb02.Y03.Cr12 Y04.Cb04.Y05.Cr14.Y06.Cb06.Y07.Cr16 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ *Ft Y10.Cb00.Y11.Cr10.Y12.Cb02.Y13.Cr12 Y14.Cb04.Y15.Cr14.Y16.Cb06.Y17.Cr16 * ^ ^ ^ ^ ^ ^ ^ ^ *Fb Y10.Cb00.Y11.Cr10.Y12.Cb02.Y13.Cr12 Y14.Cb04.Y15.Cr14.Y16.Cb06.Y17.Cr16 * ^ ^ ^ ^ ^ ^ ^ ^ * * lavtools unpacking into 4:2:0-planar * *Ft Y00.Y01.Y02.Y03.Y04.Y05.Y06.Y07... *Fb Y00.Y01.Y02.Y03.Y04.Y05.Y06.Y07... *Ft Y10.Y11.Y12.Y13.Y14.Y15.Y16.Y17... *Fb Y10.Y11.Y12.Y13.Y14.Y15.Y16.Y17... * *Ft Cb00.Cb02.Cb04.Cb06... *Fb Cb00.Cb02.Cb04.Cb06... * *Ft Cr10.Cr12.Cr14.Cr16... *Fb Cr10.Cr12.Cr14.Cr16... * *//* * Unpack libdv's 4:2:2-packed into our 4:2:0-planar, * treating each interlaced field independently * */void frame_YUV422_to_YUV420P(uint8_t **output, uint8_t *input, int width, int height){ int i, j, w2; uint8_t *y, *cb, *cr; w2 = width/2; y = output[0]; cb = output[1]; cr = output[2]; for (i=0; i<height; i+=4) { /* process two scanlines (one from each field, interleaved) */ /* ...top-field scanline */ for (j=0; j<w2; j++) { /* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] */ *(y++) = *(input++); *(cb++) = *(input++); *(y++) = *(input++); *(cr++) = *(input++); } /* ...bottom-field scanline */ for (j=0; j<w2; j++) { /* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] */ *(y++) = *(input++); *(cb++) = *(input++); *(y++) = *(input++); *(cr++) = *(input++); } /* process next two scanlines (one from each field, interleaved) */ /* ...top-field scanline */ for (j=0; j<w2; j++) { /* skip every second line for U and V */ *(y++) = *(input++); input++; *(y++) = *(input++); input++; } /* ...bottom-field scanline */ for (j=0; j<w2; j++) { /* skip every second line for U and V */ *(y++) = *(input++); input++; *(y++) = *(input++); input++; } }}#define FOURCC_I420 0x30323449#define FOURCC_I422 0x32323449#ifdef HAVE_SDLint frame_planar_to_packed(uint8_t *output, uint8_t **input, int width, int height, int ofmt, int ifmt, int interlaced){ uint8_t *y, *u, *v, *sy, *su, *sv, *sye, *su0, *sv0; int dy, dc, cw, scw, ch, scdv, scdh, ln, sln, px, spx; ch = height; cw = scw = width;#define DIV_MAX 4 scdv = scdh = DIV_MAX; switch (ofmt) { case SDL_YUY2_OVERLAY: scdh /= 2; cw /= 2; y = output; dy = 2; u = output + 1; v = output + 3; dc = 4; break; case SDL_UYVY_OVERLAY: scdh /= 2; cw /= 2; y = output + 1; dy = 2; u = output; v = output + 2; dc = 4; break; case SDL_YVYU_OVERLAY: scdh /= 2; cw /= 2; y = output; dy = 2; u = output + 3; v = output + 1; dc = 4; break; default: return 1; } switch (ifmt) { case FOURCC_I420: scdv *= 2; case FOURCC_I422: scdh *= 2; scw /= 2; sy = input[0]; su0 = input[1]; sv0 = input[2]; break; default: return 1; } sye = sy + (width * height); while (sy < sye) { *y = *sy++; y += dy; } for (ln = 0; ln < ch; ln++) { sln = ln * DIV_MAX / scdv; if (interlaced) { sln &= ~1; sln |= (ln & 1); } su = su0 + (sln * scw); sv = sv0 + (sln * scw); for (px = 0; px < cw; px++) { spx = px * DIV_MAX / scdh; *u = su[spx]; u += dc; *v = sv[spx]; v += dc; } } return 0;}#endif/* On some systems MAP_FAILED seems to be missing */#ifndef MAP_FAILED#define MAP_FAILED ( (caddr_t) -1 )#endif#define MJPEG_MAX_BUF 64#define HZ 100#define VALUE_NOT_FILLED -10000typedef struct { uint8_t*buff; /* the buffer for JPEG frames */ int video_fd; /* the file descriptor for the video device */ struct mjpeg_requestbuffers br; /* buffer requests */ uint8_t*tmpbuff[2]; /* buffers for flicker reduction */ double spvf; /* seconds per video frame */ int usec_per_frame; /* milliseconds per frame */ int min_frame_num; /* the lowest frame to be played back - normally 0 */ int max_frame_num; /* the latest frame to be played back - normally num_frames - 1 */ int current_frame_num; /* the current frame */ int current_playback_speed; /* current playback speed */ long old_field_len; int old_buff_no; int currently_processed_frame; /* changes constantly */ int currently_synced_frame; /* changes constantly */ int show_top; /* changes constantly */ int first_frame; /* software sync variable */ struct timeval lastframe_completion; /* software sync variable */#ifdef HAVE_SDL SDL_Surface *screen; /* the screen object used for software playback */ SDL_Rect jpegdims; /* a SDL rectangle */ SDL_Overlay *yuv_overlay; /* SDL YUV overlay */ pthread_t software_playback_thread; /* the thread for software playback */ pthread_mutex_t valid_mutex; int valid[MJPEG_MAX_BUF]; /* Non-zero if buffer has been filled - num of frames to be played */ pthread_cond_t buffer_filled[MJPEG_MAX_BUF]; pthread_cond_t buffer_done[MJPEG_MAX_BUF]; pthread_mutex_t syncinfo_mutex; long buffer_entry[MJPEG_MAX_BUF]; long currently_processed_entry; int yuvformat; uint8_t *yuvbuff[3];# ifdef HAVE_LIBDV dv_decoder_t *decoder; int pitches[3];# endif#endif int data_format[MJPEG_MAX_BUF]; struct mjpeg_sync syncinfo[MJPEG_MAX_BUF]; /* synchronization info */ unsigned long *save_list; /* for editing purposes */ long save_list_len; /* for editing purposes */ uint8_t abuff[16384]; /* the audio buffer */ double spas; /* seconds per audio sample */ long audio_buffer_size; /* audio stream buffer size */ int audio_mute; /* controls whether to currently play audio or not */ int state; /* playing, paused or stoppped */ pthread_t playback_thread; /* the thread for the whole playback-library */} video_playback_setup;/****************************************************** * lavplay_msg() * simplicity function which will give messages ******************************************************/static void lavplay_msg(int type, lavplay_t *info, const char format[], ...) GNUC_PRINTF(3,4);static void lavplay_msg(int type, lavplay_t *info, const char format[], ...){ char buf[1024]; va_list args; va_start(args, format); vsnprintf(buf, sizeof(buf)-1, format, args); va_end(args); if (!info) /* we can't let errors pass without giving notice */ mjpeg_error("**ERROR: %s", buf); else if (info->msg_callback) info->msg_callback(type, buf); else if (type == LAVPLAY_MSG_ERROR) mjpeg_error("**ERROR: %s", buf);}/****************************************************** * lavplay_change_state() * change the state ******************************************************/static void lavplay_change_state(lavplay_t *info, int new_state){ video_playback_setup *settings = (video_playback_setup *)info->settings; /*EditList *editlist = info->editlist; */ settings->state = new_state;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?