liblavplay.c
来自「Motion JPEG编解码器源代码」· C语言 代码 · 共 2,022 行 · 第 1/5 页
C
2,022 行
settings->yuvformat = (env? ((env[0])|(env[1]<<8)|(env[2]<<16)|(env[3]<<24)): SDL_YUY2_OVERLAY); if (!info->sdl_width) info->sdl_width = editlist->video_width; if (!info->sdl_height) info->sdl_height = editlist->video_height; if (!lavplay_SDL_init(info)) return 0; settings->yuvbuff[0] = (uint8_t *)malloc(editlist->video_width * editlist->video_height * 2); if (!settings->yuvbuff[0]) { lavplay_msg (LAVPLAY_MSG_ERROR, info, "Malloc error, you\'re probably out of memory"); return 0; } settings->yuvbuff[1] = settings->yuvbuff[0] + (editlist->video_width * editlist->video_height); settings->yuvbuff[2] = settings->yuvbuff[0] + (editlist->video_width * editlist->video_height * 3 / 2);# ifdef HAVE_LIBDV settings->decoder = dv_decoder_new(0,0,0); settings->decoder->quality = DV_QUALITY_BEST;# endif }#endif if (editlist->has_audio && info->audio) { if (audio_init(0, 0, (editlist->audio_chans>1), editlist->audio_bits, editlist->audio_rate)) /* increase this last argument to test sync */ { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Error initializing Audio: %s",audio_strerror()); return 0; } settings->audio_buffer_size = audio_get_buffer_size(); } /* After we have fired up the audio and video threads system (which * are assisted if we're installed setuid root, we want to set the * effective user id to the real user id */ if(seteuid(getuid()) < 0) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Can't set effective user-id: %s", strerror(errno)); return 0; } /* Fill all buffers first */ for(nqueue=0;nqueue<settings->br.count;nqueue++) { if (!lavplay_queue_next_frame(info, settings->buff+nqueue* settings->br.size, (settings->data_format[nqueue] = el_video_frame_data_format(settings->current_frame_num, editlist)), 0,0,0)) break; } /* Choose the correct parameters for playback */ if (!lavplay_mjpeg_get_params(info, &bp)) return 0; /* set options */ bp.input = 0; bp.norm = (editlist->video_norm == 'n') ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; lavplay_msg(LAVPLAY_MSG_INFO, info, "Output norm: %s", bp.norm==VIDEO_MODE_NTSC?"NTSC":"PAL"); hn = bp.norm==VIDEO_MODE_NTSC?480:576; /* Height of norm */ if (info->playback_mode != 'S') {#ifdef HAVE_V4L /* set correct width of device for hardware * DC10(+): 768 (PAL/SECAM) or 640 (NTSC), Buz/LML33: 720 */ if (ioctl(settings->video_fd, VIDIOCGCAP, &vc) < 0) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Error getting device capabilities: %s", strerror(errno)); return 0; } /* vc.maxwidth is often reported wrong - let's just keep it broken (sigh) */ if (vc.maxwidth != 768 && vc.maxwidth != 640) vc.maxwidth = 720; bp.decimation = 0; /* we will set proper params ourselves later on */ if (editlist->video_width > vc.maxwidth || editlist->video_height > hn ) { /* the video is too big */ lavplay_msg(LAVPLAY_MSG_ERROR, info, "Video dimensions too large: %ld x %ld, device max = %dx%d", editlist->video_width, editlist->video_height, vc.maxwidth, hn); return 0; } /* if zoom_to_fit is set, HorDcm is independent of interlacing */ if (info->zoom_to_fit) { if (editlist->video_width <= vc.maxwidth/4 ) bp.HorDcm = 4; else if (editlist->video_width <= vc.maxwidth/2) bp.HorDcm = 2; else bp.HorDcm = 1; } if (editlist->video_inter) { /* Interlaced video, 2 fields per buffer */ bp.field_per_buff = 2; bp.TmpDcm = 1; if (info->zoom_to_fit) { if (editlist->video_height <= hn/2) bp.VerDcm = 2; else bp.VerDcm = 1; } else { /* if zoom_to_fit is not set, we always use decimation 1 */ bp.HorDcm = 1; bp.VerDcm = 1; } } else { /* Not interlaced, 1 field per buffer */ bp.field_per_buff = 1; bp.TmpDcm = 2; if (editlist->video_height > hn/2 || (!info->zoom_to_fit && editlist->video_width > vc.maxwidth/2)) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "Video dimensions (not interlaced) too large: %ld x %ld", editlist->video_width, editlist->video_height); if (editlist->video_width > vc.maxwidth/2) lavplay_msg(LAVPLAY_MSG_ERROR, info, "Try using the \'zoom-to-fit\'-option"); return 0; } if(info->zoom_to_fit) { if (editlist->video_height <= hn/4 ) bp.VerDcm = 2; else bp.VerDcm = 1; } else { /* the following is equivalent to decimation 2 in lavrec: */ bp.HorDcm = 2; bp.VerDcm = 1; } } /* calculate height, width and offsets from the above settings */ bp.quality = 100; bp.img_width = bp.HorDcm * editlist->video_width; bp.img_height = bp.VerDcm * editlist->video_height/bp.field_per_buff; if (info->horizontal_offset == VALUE_NOT_FILLED) bp.img_x = (vc.maxwidth - bp.img_width)/2; else bp.img_x = info->horizontal_offset; if (info->vertical_offset == VALUE_NOT_FILLED) bp.img_y = (hn/2 - bp.img_height)/2; else bp.img_y = info->vertical_offset/2; lavplay_msg(LAVPLAY_MSG_INFO, info, "Output dimensions: %dx%d+%d+%d", bp.img_width, bp.img_height*2, bp.img_x, bp.img_y*2); lavplay_msg(LAVPLAY_MSG_INFO, info, "Output zoom factors: %d (hor) %d (ver)", bp.HorDcm,bp.VerDcm*bp.TmpDcm);#else fprintf(stderr, "No video4linux support!\n"); return 0;#endif }#ifdef HAVE_SDL else { /* software playback */ lavplay_msg(LAVPLAY_MSG_INFO, info, "Output dimensions: %ldx%ld", editlist->video_width, editlist->video_height); }#endif /* Set field polarity for interlaced video */ bp.odd_even = (editlist->video_inter==LAV_INTER_TOP_FIRST); /*if (info->exchange_fields) bp.odd_even = !bp.odd_even; */ /*this is already done by the open_files() function */ /* Set these settings */ if (!lavplay_mjpeg_set_params(info, &bp)) return 0; if (!lavplay_mjpeg_set_playback_rate(info, editlist->video_fps, editlist->video_norm=='p'?0:1)) return 0; return 1;}/****************************************************** * lavplay_playback_cycle() * the playback cycle ******************************************************/static void lavplay_playback_cycle(lavplay_t *info){ video_playback_stats stats; video_playback_setup *settings = (video_playback_setup *)info->settings; EditList *editlist = info->editlist; struct mjpeg_sync bs; struct timeval audio_tmstmp; struct timeval time_now; double tdiff1, tdiff2; int n; int first_free, frame, skipv, skipa, skipi, nvcorr; long frame_number[256]; /* Must be at least as big as the number of buffers used */ stats.stats_changed = 0; stats.num_corrs_a = 0; stats.num_corrs_b = 0; stats.nqueue = 0; stats.nsync = 0; stats.audio = 0; stats.norm = editlist->video_norm=='n'?1:0; tdiff1 = 0.; tdiff2 = 0.; nvcorr = 0; /* Queue the buffers read, this triggers video playback */ if (editlist->has_audio && info->audio) { audio_start(); stats.audio = 1; } for(n=0;n<settings->br.count;n++) /* TODO: maybe br.count-1? */ { frame_number[n] = settings->current_frame_num; lavplay_mjpeg_queue_buf(info, n, 1); } stats.nqueue = settings->br.count; while (settings->state != LAVPLAY_STATE_STOP) { /* Sync to get a free buffer. We want to have all free buffers, * which have been played so far. Normally there should be a function * in the kernel API to get the number of all free buffers. * I don't want to change this API at the moment, therefore * we look on the clock to see if there are more buffers ready */ first_free = stats.nsync; do { if (settings->state == LAVPLAY_STATE_STOP) goto FINISH; if (!lavplay_mjpeg_sync_buf(info, &bs)) { lavplay_change_state(info, LAVPLAY_STATE_STOP); goto FINISH; } frame = bs.frame; /* Since we queue the frames in order, we have to get them back in order */ if (frame != stats.nsync % settings->br.count) { lavplay_msg(LAVPLAY_MSG_ERROR, info, "**INTERNAL ERROR: Bad frame order on sync: frame = %d, nsync = %d, br.count = %ld", frame, stats.nsync, settings->br.count); lavplay_change_state(info, LAVPLAY_STATE_STOP); goto FINISH; } stats.nsync++; /* Look on clock */ gettimeofday(&time_now, 0); stats.tdiff = time_now.tv_sec - bs.timestamp.tv_sec + (time_now.tv_usec - bs.timestamp.tv_usec)*1.e-6; } while (stats.tdiff > settings->spvf && (stats.nsync - first_free) < settings->br.count - 1); if ((stats.nsync - first_free) > settings->br.count - 3) lavplay_msg(LAVPLAY_MSG_WARNING, info, "Disk too slow, can not keep pace!"); if (editlist->has_audio && info->audio) { audio_get_output_status(&audio_tmstmp, &(stats.num_asamps), &(stats.num_aerr)); if (audio_tmstmp.tv_sec) { tdiff1 = settings->spvf * (stats.nsync - nvcorr) - settings->spas * settings->audio_buffer_size / editlist->audio_bps * stats.num_asamps; tdiff2 = (bs.timestamp.tv_sec - audio_tmstmp.tv_sec) + (bs.timestamp.tv_usec - audio_tmstmp.tv_usec) * 1.e-6; } } stats.tdiff = tdiff1 - tdiff2; /* Fill and queue free buffers again */ for (n=first_free;n<stats.nsync;) { /* Audio/Video sync correction */ skipv = 0; skipa = 0; skipi = 0; if (info->sync_correction) { if (stats.tdiff > settings->spvf) { /* Video is ahead audio */ skipa = 1; if (info->sync_ins_frames) skipi = 1; nvcorr++; stats.num_corrs_a++; stats.tdiff -= settings->spvf; stats.stats_changed = 1; } if (stats.tdiff < -settings->spvf) { /* Video is behind audio */ skipv = 1; if (!info->sync_skip_frames) skipi = 1; nvcorr--; stats.num_corrs_b++; stats.tdiff += settings->spvf; stats.stats_changed = 1; } } /* Read one frame, break if EOF is reached */ frame = n % settings->br.count; frame_number[frame] = settings->current_frame_num;#ifdef HAVE_SDL settings->buffer_entry[frame] = editlist->frame_list[settings->current_frame_num];#endif if (!lavplay_queue_next_frame(info, settings->buff+frame*settings->br.size, (settings->data_format[frame] = el_video_frame_data_format(settings->current_frame_num, editlist)), skipv,skipa,skipi)) { lavplay_change_state(info, LAVPLAY_STATE_STOP); goto FINISH; } if (skipv) continue; /* no frame has been read */ /* Queue the frame */ if (!lavplay_mjpeg_queue_buf(info, frame, 1)) { lavplay_change_state(info, LAVPLAY_STATE_STOP); goto FINISH; } stats.nqueue++; n++; } /* output statistics */ if (editlist->has_audio && info->audio) stats.audio = settings->audio_mute?0:1; stats.play_speed = settings->current_playback_speed; stats.frame = settings->current_frame_num; if (info->output_statistics) info->output_statistics(&stats); stats.stats_changed = 0; }FINISH: /* All buffers are queued, sync on the outstanding buffers * Never try to sync on the last buffer, it is a hostage of * the codec since it is played over and over again */ /* NOTE: this causes lockup for some reason - so just leave it */ /*while (stats.nqueue > stats.nsync + 1) */ /*{ */ /* lavplay_mjpeg_sync_buf(info, &bs); */ /* stats.nsync++; */ /*} */ /* and we also don't need audio anymore */ if (editlist->has_audio && info->audio) audio_shutdown();}/****************************************************** * lavplay_playback_thread() * The main playback thread ******************************************************/st
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?