/* * OSD menu */ int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; id->p_decoder->fmt_in.i_cat = SPU_ES; id->p_encoder->fmt_out.psz_language = strdup( "osd" ); if( p_sys->i_osdcodec != 0 || p_sys->psz_osdenc ) { msg_Dbg( p_stream, "creating osdmenu transcoding from fcc=`%4.4s' " "to fcc=`%4.4s'", (char*)&id->p_encoder->fmt_out.i_codec, (char*)&p_sys->i_osdcodec ); /* Complete destination format */ id->p_encoder->fmt_out.i_codec = p_sys->i_osdcodec; /* Open encoder */ es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat, VLC_CODEC_YUVA ); id->p_encoder->fmt_in.psz_language = strdup( "osd" ); id->p_encoder->p_cfg = p_sys->p_osd_cfg; id->p_encoder->p_module = module_need( id->p_encoder, "encoder", p_sys->psz_osdenc, true ); if( !id->p_encoder->p_module ) { msg_Err( p_stream, "cannot find spu encoder (%s)", p_sys->psz_osdenc ); goto error; } /* open output stream */ id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out ); id->b_transcode = true; if( !id->id ) goto error; } else { msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')", (char*)&id->p_decoder->fmt_out.i_codec ); id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_decoder->fmt_out ); id->b_transcode = false; if( !id->id ) goto error; } if( !p_sys->p_spu ) p_sys->p_spu = spu_Create( p_stream ); return VLC_SUCCESS; error: msg_Err( p_stream, "starting osd encoding thread failed" ); if( id->p_encoder->p_module ) module_unneed( id->p_encoder, id->p_encoder->p_module ); p_sys->b_osd = false; return VLC_EGENERIC; }
static int transcode_video_encoder_open( sout_stream_t *p_stream, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; msg_Dbg( p_stream, "destination (after video filters) %ix%i", id->p_encoder->fmt_in.video.i_width, id->p_encoder->fmt_in.video.i_height ); id->p_encoder->p_module = module_need( id->p_encoder, "encoder", p_sys->psz_venc, true ); if( !id->p_encoder->p_module ) { msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)", p_sys->psz_venc ? p_sys->psz_venc : "any", (char *)&p_sys->i_vcodec ); return VLC_EGENERIC; } id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec; /* */ id->p_encoder->fmt_out.i_codec = vlc_fourcc_GetCodec( VIDEO_ES, id->p_encoder->fmt_out.i_codec ); id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out ); if( !id->id ) { msg_Err( p_stream, "cannot add this stream" ); return VLC_EGENERIC; } return VLC_SUCCESS; }
static sout_stream_id_sys_t *Add(sout_stream_t *stream, const es_format_t *fmt) { sout_stream_sys_t *sys = stream->p_sys; sout_stream_id_sys_t *id = malloc(sizeof (*id)); if (unlikely(id == NULL)) return NULL; id->next = NULL; if (es_format_Copy(&id->fmt, fmt)) { es_format_Clean(&id->fmt); free(id); return NULL; } if (sys->stream != NULL) id->id = sout_StreamIdAdd(sys->stream, &id->fmt); id->prev = sys->last; sys->last = id; if (id->prev != NULL) id->prev->next = id; else sys->first = id; return id; }
bool transcode_audio_add( sout_stream_t *p_stream, es_format_t *p_fmt, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; msg_Dbg( p_stream, "creating audio transcoding from fcc=`%4.4s' to fcc=`%4.4s'", (char*)&p_fmt->i_codec, (char*)&p_sys->i_acodec ); /* Complete destination format */ id->p_encoder->fmt_out.i_codec = p_sys->i_acodec; id->p_encoder->fmt_out.audio.i_rate = p_sys->i_sample_rate > 0 ? p_sys->i_sample_rate : p_fmt->audio.i_rate; id->p_encoder->fmt_out.i_bitrate = p_sys->i_abitrate; id->p_encoder->fmt_out.audio.i_bitspersample = p_fmt->audio.i_bitspersample; id->p_encoder->fmt_out.audio.i_channels = p_sys->i_channels > 0 ? p_sys->i_channels : p_fmt->audio.i_channels; /* Sanity check for audio channels */ id->p_encoder->fmt_out.audio.i_channels = __MIN( id->p_encoder->fmt_out.audio.i_channels, id->p_decoder->fmt_in.audio.i_channels ); id->p_encoder->fmt_out.audio.i_original_channels = id->p_decoder->fmt_in.audio.i_physical_channels; if( id->p_decoder->fmt_in.audio.i_channels == id->p_encoder->fmt_out.audio.i_channels ) { id->p_encoder->fmt_out.audio.i_physical_channels = id->p_decoder->fmt_in.audio.i_physical_channels; } else { id->p_encoder->fmt_out.audio.i_physical_channels = pi_channels_maps[id->p_encoder->fmt_out.audio.i_channels]; } /* Build decoder -> filter -> encoder chain */ if( transcode_audio_new( p_stream, id ) ) { msg_Err( p_stream, "cannot create audio chain" ); return false; } /* Open output stream */ id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out ); id->b_transcode = true; if( !id->id ) { transcode_audio_close( id ); return false; } date_Init( &id->interpolated_pts, p_fmt->audio.i_rate, 1 ); return true; }
static int OutputNew( sout_stream_t *p_stream, const char *psz_muxer, const char *psz_prefix, const char *psz_extension ) { sout_stream_sys_t *p_sys = p_stream->p_sys; char *psz_file = NULL; char *psz_output = NULL; int i_count; if( asprintf( &psz_file, "%s%s%s", psz_prefix, psz_extension ? "." : "", psz_extension ? psz_extension : "" ) < 0 ) { psz_file = NULL; goto error; } if( asprintf( &psz_output, "std{access=file,mux='%s',dst='%s'}", psz_muxer, psz_file ) < 0 ) { psz_output = NULL; goto error; } /* Create the output */ msg_Dbg( p_stream, "Using record output `%s'", psz_output ); p_sys->p_out = sout_StreamChainNew( p_stream->p_sout, psz_output, NULL, NULL ); if( !p_sys->p_out ) goto error; /* Add es */ i_count = 0; for( int i = 0; i < p_sys->i_id; i++ ) { sout_stream_id_t *id = p_sys->id[i]; id->id = sout_StreamIdAdd( p_sys->p_out, &id->fmt ); if( id->id ) i_count++; } if( psz_file && psz_extension ) var_SetString( p_stream->p_libvlc, "record-file", psz_file ); free( psz_file ); free( psz_output ); return i_count; error: free( psz_file ); free( psz_output ); return -1; }
/***************************************************************************** * Add: *****************************************************************************/ static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt ) { sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_id_sys_t *id; int i_stream, i_valid_streams = 0; id = malloc( sizeof( sout_stream_id_sys_t ) ); if( !id ) return NULL; TAB_INIT( id->i_nb_ids, id->pp_ids ); msg_Dbg( p_stream, "duplicated a new stream codec=%4.4s (es=%d group=%d)", (char*)&p_fmt->i_codec, p_fmt->i_id, p_fmt->i_group ); for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ ) { void *id_new = NULL; if( ESSelected( p_fmt, p_sys->ppsz_select[i_stream] ) ) { sout_stream_t *out = p_sys->pp_streams[i_stream]; id_new = (void*)sout_StreamIdAdd( out, p_fmt ); if( id_new ) { msg_Dbg( p_stream, " - added for output %d", i_stream ); i_valid_streams++; } else { msg_Dbg( p_stream, " - failed for output %d", i_stream ); } } else { msg_Dbg( p_stream, " - ignored for output %d", i_stream ); } /* Append failed attempts as well to keep track of which pp_id * belongs to which duplicated stream */ TAB_APPEND( id->i_nb_ids, id->pp_ids, id_new ); } if( i_valid_streams <= 0 ) { Del( p_stream, id ); return NULL; } return id; }
bool transcode_spu_add( sout_stream_t *p_stream, es_format_t *p_fmt, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; if( p_sys->i_scodec || p_sys->psz_senc ) { msg_Dbg( p_stream, "creating subtitles transcoding from fcc=`%4.4s' " "to fcc=`%4.4s'", (char*)&p_fmt->i_codec, (char*)&p_sys->i_scodec ); /* Complete destination format */ id->p_encoder->fmt_out.i_codec = p_sys->i_scodec; /* build decoder -> filter -> encoder */ if( transcode_spu_new( p_stream, id ) ) { msg_Err( p_stream, "cannot create subtitles chain" ); return false; } /* open output stream */ id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out ); id->b_transcode = true; if( !id->id ) { transcode_spu_close( p_stream, id ); return false; } } else { assert( p_sys->b_soverlay ); msg_Dbg( p_stream, "subtitles (fcc=`%4.4s') overlaying", (char*)&p_fmt->i_codec ); id->b_transcode = true; /* Build decoder -> filter -> overlaying chain */ if( transcode_spu_new( p_stream, id ) ) { msg_Err( p_stream, "cannot create subtitles chain" ); return false; } } return true; }
static int AddStream(sout_stream_t *stream, char *chain) { sout_stream_sys_t *sys = stream->p_sys; msg_Dbg(stream, "starting new phase \"%s\"", chain); /* TODO format */ sys->stream = sout_StreamChainNew(stream->p_sout, chain, stream->p_next, NULL); if (sys->stream == NULL) return -1; for (sout_stream_id_sys_t *id = sys->first; id != NULL; id = id->next) id->id = sout_StreamIdAdd(sys->stream, &id->fmt); return 0; }
static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt ) { sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys; sout_stream_id_sys_t *id; id = malloc( sizeof( sout_stream_id_sys_t ) ); if( unlikely( !id ) ) return NULL; id->id = p_fmt->i_id; switch( p_fmt->i_cat) { case VIDEO_ES: id->type = "Video"; break; case AUDIO_ES: id->type = "Audio"; break; case SPU_ES: id->type = "SPU"; break; default: id->type = "Data"; break; } id->next_id = NULL; id->segment_number = 0; id->previous_dts = VLC_TICK_INVALID; id->track_duration = 0; InitMD5( &id->hash ); msg_Dbg( p_stream, "%s: Adding track type:%s id:%d", p_sys->prefix, id->type, id->id); if( p_stream->p_next ) id->next_id = sout_StreamIdAdd( p_stream->p_next, p_fmt ); return id; }
int sout_stream_sys_t::UpdateOutput( sout_stream_t *p_stream ) { assert( p_stream->p_sys == this ); if ( es_changed ) { es_changed = false; bool canRemux = true; vlc_fourcc_t i_codec_video = 0, i_codec_audio = 0; for (std::vector<sout_stream_id_sys_t*>::iterator it = streams.begin(); it != streams.end(); ++it) { const es_format_t *p_es = &(*it)->fmt; if (p_es->i_cat == AUDIO_ES) { if (!canDecodeAudio( p_es )) { msg_Dbg( p_stream, "can't remux audio track %d codec %4.4s", p_es->i_id, (const char*)&p_es->i_codec ); canRemux = false; } else if (i_codec_audio == 0) i_codec_audio = p_es->i_codec; } else if (b_has_video && p_es->i_cat == VIDEO_ES) { if (!canDecodeVideo( p_es )) { msg_Dbg( p_stream, "can't remux video track %d codec %4.4s", p_es->i_id, (const char*)&p_es->i_codec ); canRemux = false; } else if (i_codec_video == 0) i_codec_video = p_es->i_codec; } } std::stringstream ssout; if ( !canRemux ) { if ( i_codec_audio == 0 ) i_codec_audio = DEFAULT_TRANSCODE_AUDIO; /* avcodec AAC encoder is experimental */ if ( i_codec_audio == VLC_CODEC_MP4A || i_codec_audio == VLC_FOURCC('h', 'a', 'a', 'c') || i_codec_audio == VLC_FOURCC('l', 'a', 'a', 'c') || i_codec_audio == VLC_FOURCC('s', 'a', 'a', 'c')) i_codec_audio = DEFAULT_TRANSCODE_AUDIO; if ( i_codec_video == 0 ) i_codec_video = DEFAULT_TRANSCODE_VIDEO; /* TODO: provide audio samplerate and channels */ ssout << "transcode{acodec="; char s_fourcc[5]; vlc_fourcc_to_char( i_codec_audio, s_fourcc ); s_fourcc[4] = '\0'; ssout << s_fourcc; if ( b_has_video ) { /* TODO: provide maxwidth,maxheight */ ssout << ",vcodec="; vlc_fourcc_to_char( i_codec_video, s_fourcc ); s_fourcc[4] = '\0'; ssout << s_fourcc; } ssout << "}:"; } std::string mime; if ( !b_has_video && default_muxer == DEFAULT_MUXER ) mime = "audio/x-matroska"; else if ( i_codec_audio == VLC_CODEC_VORBIS && i_codec_video == VLC_CODEC_VP8 && default_muxer == DEFAULT_MUXER ) mime = "video/webm"; else mime = default_mime; ssout << "http{dst=:" << i_port << "/stream" << ",mux=" << default_muxer << ",access=http{mime=" << mime << "}}"; if ( sout != ssout.str() ) { if ( unlikely( p_out != NULL ) ) { sout_StreamChainDelete( p_out, p_out ); sout = ""; } p_out = sout_StreamChainNew( p_stream->p_sout, ssout.str().c_str(), NULL, NULL); if (p_out == NULL) { msg_Dbg(p_stream, "could not create sout chain:%s", ssout.str().c_str()); return VLC_EGENERIC; } sout = ssout.str(); } /* check the streams we can actually add */ for (std::vector<sout_stream_id_sys_t*>::iterator it = streams.begin(); it != streams.end(); ++it) { sout_stream_id_sys_t *p_sys_id = *it; p_sys_id->p_sub_id = sout_StreamIdAdd( p_out, &p_sys_id->fmt ); if ( p_sys_id->p_sub_id == NULL ) { msg_Err( p_stream, "can't handle a stream" ); streams.erase( it, it ); } } /* tell the chromecast to load the content */ p_intf->setHasInput( true, mime ); } return VLC_SUCCESS; }
static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) { sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_id_t *id; id = calloc( 1, sizeof( sout_stream_id_t ) ); if( !id ) goto error; id->id = NULL; id->p_decoder = NULL; id->p_encoder = NULL; /* Create decoder object */ id->p_decoder = vlc_object_create( p_stream, sizeof( decoder_t ) ); if( !id->p_decoder ) goto error; id->p_decoder->p_module = NULL; id->p_decoder->fmt_in = *p_fmt; id->p_decoder->b_pace_control = true; /* Create encoder object */ id->p_encoder = sout_EncoderCreate( p_stream ); if( !id->p_encoder ) goto error; id->p_encoder->p_module = NULL; /* Create destination format */ es_format_Init( &id->p_encoder->fmt_out, p_fmt->i_cat, 0 ); id->p_encoder->fmt_out.i_id = p_fmt->i_id; id->p_encoder->fmt_out.i_group = p_fmt->i_group; if( p_sys->psz_alang ) id->p_encoder->fmt_out.psz_language = strdup( p_sys->psz_alang ); else if( p_fmt->psz_language ) id->p_encoder->fmt_out.psz_language = strdup( p_fmt->psz_language ); bool success; if( p_fmt->i_cat == AUDIO_ES && (p_sys->i_acodec || p_sys->psz_aenc) ) success = transcode_audio_add(p_stream, p_fmt, id); else if( p_fmt->i_cat == VIDEO_ES && (p_sys->i_vcodec || p_sys->psz_venc) ) success = transcode_video_add(p_stream, p_fmt, id); else if( ( p_fmt->i_cat == SPU_ES ) && ( p_sys->i_scodec || p_sys->psz_senc || p_sys->b_soverlay ) ) success = transcode_spu_add(p_stream, p_fmt, id); else if( !p_sys->b_osd && (p_sys->i_osdcodec != 0 || p_sys->psz_osdenc) ) success = transcode_osd_add(p_stream, p_fmt, id); else { msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')", (char*)&p_fmt->i_codec ); id->id = sout_StreamIdAdd( p_stream->p_next, p_fmt ); id->b_transcode = false; success = id->id; } if(!success) goto error; return id; error: if( id ) { if( id->p_decoder ) { vlc_object_release( id->p_decoder ); id->p_decoder = NULL; } if( id->p_encoder ) { es_format_Clean( &id->p_encoder->fmt_out ); vlc_object_release( id->p_encoder ); id->p_encoder = NULL; } free( id ); } return NULL; }
/***************************************************************************** * Add: *****************************************************************************/ static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, const es_format_t *p_fmt ) { sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_id_sys_t *id; int i; /* search a compatible output */ for( i = 0; i < p_sys->i_id; i++ ) { id = p_sys->id[i]; if( id->b_used ) continue; if( id->fmt.i_cat != p_fmt->i_cat || id->fmt.i_codec != p_fmt->i_codec ) continue; if( id->fmt.i_cat == AUDIO_ES ) { audio_format_t *p_a = &id->fmt.audio; if( p_a->i_rate != p_fmt->audio.i_rate || p_a->i_channels != p_fmt->audio.i_channels || p_a->i_blockalign != p_fmt->audio.i_blockalign ) continue; } else if( id->fmt.i_cat == VIDEO_ES ) { video_format_t *p_v = &id->fmt.video; if( p_v->i_width != p_fmt->video.i_width || p_v->i_height != p_fmt->video.i_height ) continue; } /* */ msg_Dbg( p_stream, "reusing already opened output" ); id->b_used = true; id->b_streamswap = true; return id; } /* destroy all outputs from the same category */ for( i = 0; i < p_sys->i_id; i++ ) { id = p_sys->id[i]; if( !id->b_used && id->fmt.i_cat == p_fmt->i_cat ) { TAB_REMOVE( p_sys->i_id, p_sys->id, id ); sout_StreamIdDel( p_stream->p_next, id->id ); es_format_Clean( &id->fmt ); free( id ); i = 0; continue; } } msg_Dbg( p_stream, "creating new output" ); id = malloc( sizeof( sout_stream_id_sys_t ) ); if( id == NULL ) return NULL; es_format_Copy( &id->fmt, p_fmt ); id->b_streamswap = false; id->b_used = true; id->id = sout_StreamIdAdd( p_stream->p_next, &id->fmt ); if( id->id == NULL ) { free( id ); return NULL; } TAB_APPEND( p_sys->i_id, p_sys->id, id ); return id; }
/***************************************************************************** * Sout callbacks *****************************************************************************/ static sout_stream_id_sys_t *Add(sout_stream_t *p_stream, const es_format_t *p_fmt) { sout_stream_sys_t *p_sys = p_stream->p_sys; return sout_StreamIdAdd(p_sys->p_out, p_fmt); }