📄 switcher.c
字号:
sout_stream_sys_t *p_sys = p_stream->p_sys; if ( !id->id ) { block_Release( p_buffer ); return VLC_EGENERIC; } if ( !id->b_switcher_video && !id->b_switcher_audio ) { return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer ); } block_ChainAppend( &id->p_queued, p_buffer ); if ( id->b_switcher_video ) { /* Check for commands for every video frame. */ NetCommand( p_stream ); while ( id->p_queued != NULL ) { mtime_t i_dts = 0; int i; if ( p_sys->i_old_cmd != p_sys->i_cmd ) { i_dts = VideoCommand( p_stream, id ); } i_dts = Process( p_stream, id, i_dts ); for ( i = 0; i < MAX_AUDIO; i++ ) { if ( p_sys->pp_audio_ids[i] != NULL ) Process( p_stream, p_sys->pp_audio_ids[i], i_dts ); } } } return VLC_SUCCESS;}/***************************************************************************** * Process: Process and dispatch buffers *****************************************************************************/static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id, mtime_t i_max_dts ){ sout_stream_sys_t *p_sys = p_stream->p_sys; mtime_t i_dts = 0; block_t *p_blocks = NULL; block_t *p_blocks_out = NULL; /* Find out the blocks we need. */ while ( id->p_queued != NULL && (!i_max_dts || id->p_queued->i_dts <= i_max_dts) ) { block_t *p_next = id->p_queued->p_next; id->p_queued->p_next = NULL; i_dts = id->p_queued->i_dts; block_ChainAppend( &p_blocks, id->p_queued ); id->p_queued = p_next; } if ( p_sys->i_old_cmd == 0 ) { /* Full forward */ if ( p_blocks != NULL ) p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks ); return i_dts; } if ( p_sys->i_old_cmd == -1 ) { /* No output at all */ while ( p_blocks != NULL ) { block_t * p_next = p_blocks->p_next; block_Release( p_blocks ); p_blocks = p_next; } return i_dts; } while ( p_blocks != NULL ) { block_t * p_next = p_blocks->p_next; block_t * p_out; if ( id->b_switcher_video ) { p_out = VideoGetBuffer( p_stream, id, p_blocks ); } else { p_out = AudioGetBuffer( p_stream, id, p_blocks ); } p_blocks = p_next; if ( p_out != NULL ) { block_ChainAppend( &p_blocks_out, p_out ); } } if ( p_blocks_out != NULL ) p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks_out ); return i_dts;}/***************************************************************************** * UnpackFromFile: Read a YUV picture and store it in our format *****************************************************************************/static int UnpackFromFile( sout_stream_t *p_stream, const char *psz_file, int i_width, int i_height, picture_t *p_pic ){ int i, j; FILE *p_file = utf8_fopen( psz_file, "r" ); if ( p_file == NULL ) { msg_Err( p_stream, "file %s not found", psz_file ); return -1; } vout_InitPicture( VLC_OBJECT(p_stream), p_pic, VLC_FOURCC('I','4','2','0'), i_width, i_height, i_width * VOUT_ASPECT_FACTOR / i_height ); for ( i = 0; i < p_pic->i_planes; i++ ) { p_pic->p[i].p_pixels = malloc( p_pic->p[i].i_lines * p_pic->p[i].i_pitch ); memset( p_pic->p[i].p_pixels, 0, p_pic->p[i].i_lines * p_pic->p[i].i_pitch ); } for ( i = 0; i < i_height; i++ ) { int i_chroma; uint8_t p_buffer[i_width * 2]; uint8_t *p_char = p_buffer; uint8_t *p_y = &p_pic->p[0].p_pixels[i * p_pic->p[0].i_pitch]; uint8_t *p_u = &p_pic->p[1].p_pixels[i/2 * p_pic->p[1].i_pitch]; uint8_t *p_v = &p_pic->p[2].p_pixels[i/2 * p_pic->p[2].i_pitch]; if ( fread( p_buffer, 2, i_width, p_file ) != (size_t)i_width ) { msg_Err( p_stream, "premature end of file %s", psz_file ); fclose( p_file ); for ( i = 0; i < p_pic->i_planes; i++ ) { free( p_pic->p[i].p_pixels ); } return -1; } i_chroma = 0; for ( j = 0; j < i_width; j++ ) { uint8_t **pp_chroma = i_chroma ? &p_v : &p_u; i_chroma = !i_chroma; if ( i & 1 ) **pp_chroma = (**pp_chroma + *p_char + 1) / 2; else **pp_chroma = *p_char; (*pp_chroma)++; p_char++; *p_y++ = *p_char++; } } fclose( p_file ); return 0;}/***************************************************************************** * NetCommand: Get a command from the network *****************************************************************************/static void NetCommand( sout_stream_t *p_stream ){ sout_stream_sys_t *p_sys = p_stream->p_sys; char psz_buffer[11]; int i_len = recv( p_sys->i_fd, psz_buffer, sizeof( psz_buffer ) - 1, 0 ); if ( i_len > 0 ) { psz_buffer[i_len] = '\0'; int i_cmd = strtol( psz_buffer, NULL, 0 ); if ( i_cmd < -1 || i_cmd > p_sys->i_nb_pictures ) { msg_Err( p_stream, "got a wrong command (%d)", i_cmd ); return; } p_sys->i_cmd = i_cmd; msg_Dbg( p_stream, "new command: %d old:%d", p_sys->i_cmd, p_sys->i_old_cmd ); }}/***************************************************************************** * VideoCommand: Create/Delete a video encoder *****************************************************************************/static mtime_t VideoCommand( sout_stream_t *p_stream, sout_stream_id_t *id ){ sout_stream_sys_t *p_sys = p_stream->p_sys; if ( p_sys->i_cmd == 0 && !(id->p_queued->i_flags & BLOCK_FLAG_TYPE_I) ) { mtime_t i_dts = id->p_queued->i_dts; block_t *p_block = id->p_queued->p_next; while ( p_block != NULL ) { if ( p_block->i_flags & BLOCK_FLAG_TYPE_I ) return i_dts; i_dts = p_block->i_dts; p_block = p_block->p_next; } return 0; } p_sys->i_old_cmd = p_sys->i_cmd; if ( id->ff_enc ) { avcodec_close( id->ff_enc_c ); av_free( id->ff_enc_c ); av_free( id->p_frame ); free( id->p_buffer_out ); id->ff_enc = NULL; } if ( p_sys->i_cmd > 0 ) { /* Create a new encoder. */ int i_ff_codec = CODEC_ID_MPEG2VIDEO; int i_aspect_num, i_aspect_den; if( i_ff_codec == 0 ) { msg_Err( p_stream, "cannot find encoder" ); return 0; } id->ff_enc = avcodec_find_encoder( i_ff_codec ); if( !id->ff_enc ) { msg_Err( p_stream, "cannot find encoder (avcodec)" ); return 0; } id->ff_enc_c = avcodec_alloc_context(); /* Set CPU capabilities */ unsigned i_cpu = vlc_CPU(); id->ff_enc_c->dsp_mask = 0; if( !(i_cpu & CPU_CAPABILITY_MMX) ) { id->ff_enc_c->dsp_mask |= FF_MM_MMX; } if( !(i_cpu & CPU_CAPABILITY_MMXEXT) ) { id->ff_enc_c->dsp_mask |= FF_MM_MMXEXT; } if( !(i_cpu & CPU_CAPABILITY_3DNOW) ) { id->ff_enc_c->dsp_mask |= FF_MM_3DNOW; } if( !(i_cpu & CPU_CAPABILITY_SSE) ) { id->ff_enc_c->dsp_mask |= FF_MM_SSE; id->ff_enc_c->dsp_mask |= FF_MM_SSE2; } id->ff_enc_c->width = p_sys->p_pictures[p_sys->i_cmd-1].format.i_width; id->ff_enc_c->height = p_sys->p_pictures[p_sys->i_cmd-1].format.i_height; av_reduce( &i_aspect_num, &i_aspect_den, p_sys->i_aspect, VOUT_ASPECT_FACTOR, 1 << 30 /* something big */ ); av_reduce( &id->ff_enc_c->sample_aspect_ratio.num, &id->ff_enc_c->sample_aspect_ratio.den, i_aspect_num * (int64_t)id->ff_enc_c->height, i_aspect_den * (int64_t)id->ff_enc_c->width, 1 << 30 );#if LIBAVCODEC_BUILD >= 4754 id->ff_enc_c->time_base.num = 1; id->ff_enc_c->time_base.den = 25; /* FIXME */#else id->ff_enc_c->frame_rate = 25; /* FIXME */ id->ff_enc_c->frame_rate_base = 1;#endif id->ff_enc_c->gop_size = 200; id->ff_enc_c->max_b_frames = 0; id->ff_enc_c->flags |= CODEC_FLAG_QSCALE | CODEC_FLAG_INPUT_PRESERVED | CODEC_FLAG_LOW_DELAY; id->ff_enc_c->mb_decision = FF_MB_DECISION_SIMPLE; id->ff_enc_c->pix_fmt = PIX_FMT_YUV420P; if( avcodec_open( id->ff_enc_c, id->ff_enc ) ) { msg_Err( p_stream, "cannot open encoder" ); return 0; } id->p_buffer_out = malloc( id->ff_enc_c->width * id->ff_enc_c->height * 3 ); id->p_frame = avcodec_alloc_frame(); id->p_frame->linesize[0] = p_sys->p_pictures[p_sys->i_cmd-1].p[0].i_pitch; id->p_frame->linesize[1] = p_sys->p_pictures[p_sys->i_cmd-1].p[1].i_pitch; id->p_frame->linesize[2] = p_sys->p_pictures[p_sys->i_cmd-1].p[2].i_pitch; id->p_frame->data[0] = p_sys->p_pictures[p_sys->i_cmd-1].p[0].p_pixels; id->p_frame->data[1] = p_sys->p_pictures[p_sys->i_cmd-1].p[1].p_pixels; id->p_frame->data[2] = p_sys->p_pictures[p_sys->i_cmd-1].p[2].p_pixels; id->i_nb_pred = p_sys->i_gop; } return 0;}/***************************************************************************** * VideoGetBuffer: Build an alternate video buffer *****************************************************************************/static block_t *VideoGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer ){ sout_stream_sys_t *p_sys = p_stream->p_sys; int i_out; block_t *p_out; id->p_frame->quality = p_sys->i_qscale * powf(2.0, FF_LAMBDA_SHIFT + 7.0) / 139.0; id->p_frame->interlaced_frame = 0; id->p_frame->top_field_first = 1; id->p_frame->pts = p_buffer->i_dts; if ( id->i_nb_pred >= p_sys->i_gop ) { id->p_frame->pict_type = FF_I_TYPE;#if 0 id->p_frame->me_threshold = 0; id->p_frame->mb_threshold = 0;#endif id->i_nb_pred = 0; } else { id->p_frame->pict_type = FF_P_TYPE;#if 0 if ( id->p_frame->mb_type != NULL ) { id->p_frame->me_threshold = MAX_THRESHOLD; id->p_frame->mb_threshold = MAX_THRESHOLD; }#endif id->i_nb_pred++; } i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer_out, id->ff_enc_c->width * id->ff_enc_c->height * 3, id->p_frame ); if ( i_out <= 0 ) return NULL;#if 0 if ( id->p_frame->mb_type == NULL && id->ff_enc_c->coded_frame->pict_type != FF_I_TYPE ) { int mb_width = (id->ff_enc_c->width + 15) / 16; int mb_height = (id->ff_enc_c->height + 15) / 16; int h_chroma_shift, v_chroma_shift; int i; avcodec_get_chroma_sub_sample( id->ff_enc_c->pix_fmt, &h_chroma_shift, &v_chroma_shift ); id->p_frame->motion_subsample_log2 = id->ff_enc_c->coded_frame->motion_subsample_log2; id->p_frame->mb_type = malloc( ((mb_width + 1) * (mb_height + 1) + 1) * sizeof(uint32_t) ); vlc_memcpy( id->p_frame->mb_type, id->ff_enc_c->coded_frame->mb_type, (mb_width + 1) * mb_height * sizeof(id->p_frame->mb_type[0])); for ( i = 0; i < 2; i++ ) { int stride = ((16 * mb_width ) >> id->ff_enc_c->coded_frame->motion_subsample_log2) + 1; int height = ((16 * mb_height) >> id->ff_enc_c->coded_frame->motion_subsample_log2); int b8_stride = mb_width * 2 + 1; if ( id->ff_enc_c->coded_frame->motion_val[i] ) { id->p_frame->motion_val[i] = malloc( 2 * stride * height * sizeof(int16_t) ); vlc_memcpy( id->p_frame->motion_val[i], id->ff_enc_c->coded_frame->motion_val[i], 2 * stride * height * sizeof(int16_t) ); } if ( id->ff_enc_c->coded_frame->ref_index[i] ) { id->p_frame->ref_index[i] = malloc( b8_stride * 2 * mb_height * sizeof(int8_t) ); vlc_memcpy( id->p_frame->ref_index[i], id->ff_enc_c->coded_frame->ref_index[i], b8_stride * 2 * mb_height * sizeof(int8_t)); } } }#endif p_out = block_New( p_stream, i_out ); vlc_memcpy( p_out->p_buffer, id->p_buffer_out, i_out ); p_out->i_length = p_buffer->i_length; p_out->i_pts = p_buffer->i_dts; p_out->i_dts = p_buffer->i_dts; p_out->i_rate = p_buffer->i_rate; switch ( id->ff_enc_c->coded_frame->pict_type ) { case FF_I_TYPE: p_out->i_flags |= BLOCK_FLAG_TYPE_I; break; case FF_P_TYPE: p_out->i_flags |= BLOCK_FLAG_TYPE_P; break; case FF_B_TYPE: p_out->i_flags |= BLOCK_FLAG_TYPE_B; break; default: break; } block_Release( p_buffer ); return p_out;}/***************************************************************************** * AudioGetBuffer: Build an alternate audio buffer *****************************************************************************/static block_t *AudioGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer ){ int i_out; block_t *p_out; i_out = avcodec_encode_audio( id->ff_enc_c, id->p_buffer_out, 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE, id->p_samples ); if ( i_out <= 0 ) return NULL; p_out = block_New( p_stream, i_out ); vlc_memcpy( p_out->p_buffer, id->p_buffer_out, i_out ); p_out->i_length = p_buffer->i_length; p_out->i_pts = p_buffer->i_dts; p_out->i_dts = p_buffer->i_dts; p_out->i_rate = p_buffer->i_rate; block_Release( p_buffer ); return p_out;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -