liblavplay.c
来自「Motion JPEG编解码器源代码」· C语言 代码 · 共 2,022 行 · 第 1/5 页
C
2,022 行
"SDL Failed to initialise..."); return 0; } /* Now initialize SDL */ if (info->soft_full_screen) settings->screen = SDL_SetVideoMode(info->sdl_width, info->sdl_height, 0, SDL_HWSURFACE | SDL_FULLSCREEN); else settings->screen = SDL_SetVideoMode(info->sdl_width, info->sdl_height, 0, SDL_HWSURFACE); if (!settings->screen) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "SDL: Output screen error: %s", SDL_GetError()); return 0; } SDL_EventState(SDL_KEYDOWN, SDL_ENABLE); SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); /* since IYUV ordering is not supported by Xv accel on maddog's system * (Matrox G400 --- although, the alias I420 is, but this is not * recognized by SDL), we use YV12 instead, which is identical, * except for ordering of Cb and Cr planes... * we swap those when we copy the data to the display buffer... */ /* FIXME: Is YUY2 best 422? */ settings->yuv_overlay = SDL_CreateYUVOverlay(editlist->video_width, editlist->video_height, settings->yuvformat, settings->screen); if (!settings->yuv_overlay) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "SDL: Couldn't create SDL_yuv_overlay: %s", SDL_GetError()); return 0; } lavplay_msg(LAVPLAY_MSG_INFO, info, "SDL YUV overlay: %s", settings->yuv_overlay->hw_overlay ? "hardware" : "software" );#if 0 if(settings->yuv_overlay->pitches[0] != settings->yuv_overlay->pitches[1] || settings->yuv_overlay->pitches[0] != settings->yuv_overlay->pitches[2] ) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "SDL returned pitches[] = { %d, %d, %d }", settings->yuv_overlay->pitches[0], settings->yuv_overlay->pitches[1], settings->yuv_overlay->pitches[2]); lavplay_msg(LAVPLAY_MSG_ERROR, info, "SDL returned non-YUV422 overlay!"); return 0; }#endif settings->jpegdims.x = 0; /* This is not going to work with interlaced pics !! */ settings->jpegdims.y = 0; settings->jpegdims.w = info->sdl_width; settings->jpegdims.h = info->sdl_height; /* Lock the screen to test, and to be able to access screen->pixels */ if (!lavplay_SDL_lock(info)) return 0; /* Draw bands of color on the raw surface, as run indicator for debugging */ sbuffer = (char *)settings->screen->pixels; for ( i=0; i < settings->screen->h; ++i ) { memset(sbuffer,(i*255)/settings->screen->h, settings->screen->w * settings->screen->format->BytesPerPixel); sbuffer += settings->screen->pitch; } /* Set the windows title */ SDL_WM_SetCaption("Lavplay Video Playback", "0000000"); /* unlock, update and wait for the fun to begin */ if (!lavplay_SDL_unlock(info)) return 0; SDL_UpdateRect(settings->screen, 0, 0, settings->jpegdims.w, settings->jpegdims.h); return 1;}#endif/****************************************************** * lavplay_mjpeg_software_frame_sync() * Try to keep in sync with nominal frame rate, * timestamp frame with actual completion time * (after any deliberate sleeps etc) * * return value: 1 on success, 0 on error ******************************************************/#ifdef HAVE_SDLstatic void lavplay_mjpeg_software_frame_sync(lavplay_t *info, int frame_periods){ int usec_since_lastframe; struct timeval now; struct timespec nsecsleep; video_playback_setup *settings = (video_playback_setup *)info->settings; /*EditList *editlist = info->editlist; */ /* I really *wish* the timer was higher res on x86 Linux... 10mSec * is a *pain*. Sooo wasteful here... */ for (;;) { gettimeofday( &now, 0 ); usec_since_lastframe = now.tv_usec - settings->lastframe_completion.tv_usec; if ( usec_since_lastframe< 0) usec_since_lastframe+= 1000000; if( now.tv_sec > settings->lastframe_completion.tv_sec+1 ) usec_since_lastframe= 1000000; if( settings->first_frame || frame_periods*settings->usec_per_frame-usec_since_lastframe < (1000000)/HZ ) break; /* Assume some other process will get a time-slice before * we do... and hence the worst-case delay of 1/HZ after * sleep timer expiry will apply. Reasonable since X will * probably do something... */ nsecsleep.tv_nsec = (frame_periods*settings->usec_per_frame-usec_since_lastframe-1000000/HZ)*1000; nsecsleep.tv_sec = 0; nanosleep( &nsecsleep, NULL ); } settings->first_frame = 0; /* We are done with writing the picture - Now update all surrounding info */ gettimeofday( &(settings->lastframe_completion), 0 ); settings->syncinfo[settings->currently_processed_frame].timestamp = settings->lastframe_completion;}#endif/****************************************************** * lavplay_mjpeg_playback_thread() * the main (software) video playback thread * * return value: 1 on success, 0 on error ******************************************************/#ifdef HAVE_SDLstatic void *lavplay_mjpeg_playback_thread(void * arg){ lavplay_t *info = (lavplay_t *)arg; video_playback_setup *settings = (video_playback_setup *)info->settings; /*EditList *editlist = info->editlist; */ lavplay_msg(LAVPLAY_MSG_DEBUG, info, "Starting software playback thread"); /* Allow easy shutting down by other processes... */ pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL ); pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); while (settings->state != LAVPLAY_STATE_STOP) { pthread_mutex_lock(&(settings->valid_mutex)); while (settings->valid[settings->currently_processed_frame] == 0) { lavplay_msg(LAVPLAY_MSG_DEBUG, info, "Playback thread: sleeping for new frames (waiting for frame %d)", settings->currently_processed_frame); pthread_cond_wait(&(settings->buffer_filled[settings->currently_processed_frame]), &(settings->valid_mutex)); if (settings->state == LAVPLAY_STATE_STOP) { /* Ok, we shall exit, that's the reason for the wakeup */ lavplay_msg(LAVPLAY_MSG_DEBUG, info, "Playback thread: was told to exit"); pthread_exit(NULL); } } pthread_mutex_unlock(&(settings->valid_mutex)); /* There is one buffer to play - get ready to rock ! */ if (settings->currently_processed_entry != settings->buffer_entry[settings->currently_processed_frame] && !lavplay_SDL_update(info, settings->buff+settings->currently_processed_frame*settings->br.size, settings->data_format[settings->currently_processed_frame], settings->br.size)) { /* something went wrong - give a warning (don't exit yet) */ lavplay_msg(LAVPLAY_MSG_WARNING, info, "Error playing a frame"); } settings->currently_processed_entry = settings->buffer_entry[settings->currently_processed_frame]; /* Synchronise and timestamp current frame after sync */ lavplay_mjpeg_software_frame_sync(info, settings->valid[settings->currently_processed_frame]); settings->syncinfo[settings->currently_processed_frame].frame = settings->currently_processed_frame; pthread_mutex_lock(&(settings->valid_mutex)); settings->valid[settings->currently_processed_frame] = 0; pthread_mutex_unlock(&(settings->valid_mutex)); /* Broadcast & wake up the waiting processes */ pthread_cond_broadcast(&(settings->buffer_done[settings->currently_processed_frame])); /* Now update the internal variables */ settings->currently_processed_frame = (settings->currently_processed_frame + 1) % settings->br.count; settings->show_top = (settings->show_top) ? 0 : 1; } lavplay_msg(LAVPLAY_MSG_DEBUG, info, "Playback thread: was told to exit"); pthread_exit(NULL); return NULL;}#endif/****************************************************** * lavplay_mjpeg_open() * hardware: opens the device and allocates buffers * software: inits threads and allocates buffers * * return value: 1 on success, 0 on error ******************************************************/static int lavplay_mjpeg_open(lavplay_t *info){#ifdef HAVE_SDL int i;#endif video_playback_setup *settings = (video_playback_setup *)info->settings; EditList *editlist = info->editlist; int max_frame_size = editlist->max_frame_size; lavplay_msg(LAVPLAY_MSG_DEBUG, info, "Initializing the %s", info->playback_mode=='S'?"threading system":"video device"); switch (info->playback_mode) {#ifdef HAVE_V4L case 'H': case 'C': /* open video device */ if ((settings->video_fd = open(info->video_dev, O_RDWR)) < 0) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Error opening %s: %s", info->video_dev, strerror(errno)); return 0; } /* Request buffers */ settings->br.count = info->MJPG_numbufs; if (max_frame_size < 140*1024) max_frame_size = 140*1024; settings->br.size = (max_frame_size + 4095)&~4095; if (ioctl(settings->video_fd, MJPIOC_REQBUFS, &(settings->br)) < 0) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Error requesting buffers: %s", strerror(errno)); return 0; } /* Map the buffers */ settings->buff = mmap(0, settings->br.count * settings->br.size, PROT_READ | PROT_WRITE, MAP_SHARED, settings->video_fd, 0); if (settings->buff == MAP_FAILED) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Error mapping the video buffer: %s", strerror(errno)); return 0; } break;#endif#ifdef HAVE_SDL case 'S': /* Just allocate MJPG_nbuf buffers */ settings->br.count = info->MJPG_numbufs; settings->br.size = (max_frame_size*2 + 4095)&~4095; settings->buff = (uint8_t *)malloc(settings->br.count * settings->br.size); if (!settings->buff) { lavplay_msg (LAVPLAY_MSG_ERROR, info, "Malloc error, you\'re probably out of memory"); return 0; } pthread_mutex_init(&(settings->valid_mutex), NULL); pthread_mutex_init(&(settings->syncinfo_mutex), NULL); /* Invalidate all buffers, and initialize the conditions */ for (i=0;i<MJPEG_MAX_BUF;i++) { settings->valid[i] = 0; pthread_cond_init(&(settings->buffer_filled[i]), NULL); pthread_cond_init(&(settings->buffer_done[i]), NULL); memset(&(settings->syncinfo[i]), 0, sizeof(struct mjpeg_sync)); } /* Now do the thread magic */ settings->currently_processed_frame = 0; settings->currently_processed_entry = -1; settings->show_top = 1; /* start with top frames as default, change with mjpeg_set_params */ if (pthread_create(&(settings->software_playback_thread), NULL, lavplay_mjpeg_playback_thread, (void *)info)) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Could not create software playback thread"); return 0; } break;#endif default: lavplay_msg(LAVPLAY_MSG_ERROR, info, "lavplay_mjpeg_open(): Unknown playback mode (\'%c\')", info->playback_mode); return 0; } settings->usec_per_frame = 0; return 1;}/****************************************************** * lavplay_mjpeg_get_params() * get default parameters * * return value: 1 on success, 0 on error ******************************************************/static int lavplay_mjpeg_get_params(lavplay_t *info, struct mjpeg_params *bp){#ifdef HAVE_SDL int i;#endif#ifdef HAVE_V4L video_playback_setup *settings = (video_playback_setup *)info->settings;#endif /*EditList *editlist = info->editlist; */ switch (info->playback_mode) {#ifdef HAVE_V4L case 'H': case 'C': /* do a MJPIOC_G_PARAMS ioctl to get proper default values */ if (ioctl(settings->video_fd, MJPIOC_G_PARAMS, bp) < 0) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Error getting video parameters: %s", strerror(errno)); return 0; } break;#endif#ifdef HAVE_SDL case 'S': /* Set some necessary params */ bp->decimation = 1; bp->quality = 50; /* default compression factor 8 */ bp->odd_even = 1; bp->APPn = 0; bp->APP_len = 0; /* No APPn marker */ for(i=0;i<60;i++) bp->APP_data[i] = 0; bp->COM_len = 0; /* No COM marker */ for(i=0;i<60;i++) bp->COM_data[i] = 0; bp->VFIFO_FB = 1; memset(bp->reserved,0,sizeof(bp->reserved)); break;#endif default: lavplay_msg(LAVPLAY_MSG_ERROR, info, "lavplay_mjpeg_get_params(): Unknown playback mode (\'%c\')", info->playback_mode); return 0; } return 1;}/****************************************************** * lavplay_mjpeg_set_params() * set the parameters * * return value: 1 on success, 0 on error ******************************************************/static int lavplay_mjpeg_set_params(lavplay_t *info, struct mjpeg_params *bp){ video_playback_setup *settings = (video_playback_setup *)info->settings; /*EditList *editlist = info->editlist; */ #ifdef HAVE_V4L if (info->playback_mode == 'H') /* only when doing on-screen (hardware-decoded) output */ { struct video_window vw; struct video_capability vc; int n, screenwidth, screenheight;#ifndef X_DISPLAY_MISSING XWindowAttributes wts; Display *dpy; if (NULL == (dpy = XOpenDisplay(strchr(info->display, ':')))) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Can't open X11 display %s\n", info->display); return 0; }#endif if (ioctl(settings->video_fd, VIDIOCGCAP, &vc) < 0) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Error getting device capabilities: %s",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?