網頁

2016年5月17日 星期二

轉換 rtsp 到另一個串流 rstp, 含 vlc-log.txt

const char *const vlc_args[] = {
"-I=dummy",
"--vout=dummy",
"--network-caching=5000",
"--sout=#rtp{sdp=rtsp://:8554/ch1}", "--sout-all", "--sout-keep",
"--verbose=2",
"--file-logging", logFile,
};
int vlc_argc = sizeof(vlc_args) / sizeof(vlc_args[0]);
vlcInstance = libvlc_new(vlc_argc, vlc_args);
const char *psz_mrl = "rtsp://169.254.1.168:554/live2.sdp";
media = libvlc_media_new_location(vlcInstance, psz_mrl);
mp = libvlc_media_player_new_from_media(media);
//libvlc_media_player_set_hwnd(mp, GetDlgItem(IDC_VIEWER)->m_hWnd);

vlc-log.txt

使用 avcodec 之 av_log

vi ../modules/codec/avcodec/video.c
static decoder_t *pAvDecoder = NULL;
static void AvLogOutCallback(void *ptr, int level, const char *fmt, va_list vl)
{
    if (level > av_log_get_level()) {
        return;
    }
/*
    FILE *fp = fopen("AvLogOut.txt", "a+");
    if (fp) {
        vfprintf(fp, fmt, vl);
        fflush(fp);
        fclose(fp);
    }
*/
    if (pAvDecoder != NULL) {
        va_list vl2;
        va_copy(vl2, vl);
        int msg_len = vsnprintf(NULL, 0, fmt, vl2);
        va_end(vl2);
        if (msg_len <= 0) return;
        char *msg = malloc(msg_len + 1 + 1);
        if (!msg) return;
        msg_len = vsnprintf(msg, msg_len+1, fmt, vl);
        if (msg_len > 0) {
            msg_Dbg(pAvDecoder, "av_log: %s", msg);
        }
        free(msg);
    }
}
static int OpenVideoCodec( decoder_t *p_dec )
{
    av_log_set_callback(AvLogOutCallback);
    vlc_init_avutil(p_dec);
}

使用硬體解碼,顯示時間

const char *const vlc_args[] = {
"-I=dummy",
"--vout=dummy",
"--network-caching=5000",
"--sout=#transcode{avcodec-hw=dxva2,acodec=g711,vcodec=h264,soverlay,sfilter=marq{marquee=%Y/%m/%d %H:%M:%S.%l,x=10,y=50}}:rtp{sdp=rtsp://:8554/ch1}", "--sout-all", "--sout-keep",
"--verbose=2",
"--file-logging", logFile,
};
int vlc_argc = sizeof(vlc_args) / sizeof(vlc_args[0]);
vlcInstance = libvlc_new(vlc_argc, vlc_args);
const char *psz_mrl = "rtsp://169.254.1.168:554/live2.sdp";
media = libvlc_media_new_location(vlcInstance, psz_mrl);
mp = libvlc_media_player_new_from_media(media);

libvlc_media_release(media);
libvlc_media_player_play(mp);


vi ../modules/stream_out/transcode/transcode.c 
#define HW_TEXT N_("Hardware decoding")
#define HW_LONGTEXT N_("This allows hardware decoding when available.")
    add_string( SOUT_CFG_PREFIX "avcodec-hw", NULL, HW_TEXT,
              HW_LONGTEXT, true )
static const char *const ppsz_sout_options[] = {
    "venc", "vcodec", "vb",
    "scale", "fps", "width", "height", "vfilter", "deinterlace",
    "deinterlace-module", "threads", "aenc", "acodec", "ab", "alang",
    "afilter", "samplerate", "channels", "senc", "scodec", "soverlay",
    "sfilter", "osd", "high-priority", "maxwidth", "maxheight",
    "avcodec-hw", NULL
};
static int Open( vlc_object_t *p_this )
{
    config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
                   p_stream->p_cfg );

    char *pAvcodecHw = var_GetString(p_stream, SOUT_CFG_PREFIX"avcodec-hw");
    msg_Dbg(p_stream, "transcode.Open avcodec-hw = %s NNN", pAvcodecHw);
    if (pAvcodecHw) {
        var_Create(p_stream, "avcodec-hw", VLC_VAR_STRING);
        var_SetString(p_stream, "avcodec-hw", pAvcodecHw);
    }
}

duplicate sout 到 display, 並使用硬體解碼

const char *const vlc_args[] = {
"-I=dummy",
"--vout=dummy",
"--network-caching=5000",
"--sout=#duplicate{dst=display{avcodec-hw=dxva2},dst=rtp{sdp=rtsp://:8554/ch1}}", "--sout-all", "--sout-keep",
"--verbose=2",
"--file-logging", logFile,
};
int vlc_argc = sizeof(vlc_args) / sizeof(vlc_args[0]);
vlcInstance = libvlc_new(vlc_argc, vlc_args);
const char *psz_mrl = "rtsp://169.254.1.168:554/live2.sdp";
media = libvlc_media_new_location(vlcInstance, psz_mrl);
mp = libvlc_media_player_new_from_media(media);

libvlc_media_release(media);
libvlc_media_player_play(mp);


vi ../modules/stream_out/display.c 
#define HW_TEXT N_("Hardware decoding")
#define HW_LONGTEXT N_("This allows hardware decoding when available.")
    add_string( SOUT_CFG_PREFIX "avcodec-hw", NULL, HW_TEXT,
              HW_LONGTEXT, true )
static const char *const ppsz_sout_options[] = {
    "audio", "video", "delay", "avcodec-hw", NULL
};
static int Open( vlc_object_t *p_this )
{
    config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
                   p_stream->p_cfg );

    char *pAvcodecHw = var_GetString(p_stream, SOUT_CFG_PREFIX"avcodec-hw");
    if (pAvcodecHw) {
        var_Create(p_stream, "avcodec-hw", VLC_VAR_STRING);
        var_SetString(p_stream, "avcodec-hw", pAvcodecHw);
    }
}

使用硬體解碼撥放

const char *const vlc_args[] = {
"-I=dummy",
"--vout=dummy",
"--network-caching=5000",
"--verbose=2",
"--file-logging", logFile,
};
int vlc_argc = sizeof(vlc_args) / sizeof(vlc_args[0]);
vlcInstance = libvlc_new(vlc_argc, vlc_args);
const char *psz_mrl = "rtsp://169.254.1.168:554/live2.sdp";
media = libvlc_media_new_location(vlcInstance, psz_mrl);
libvlc_media_add_option(media, ":avcodec-hw=dxva2");
mp = libvlc_media_player_new_from_media(media);
libvlc_media_player_set_hwnd(mp, GetDlgItem(IDC_VIEWER)->m_hWnd);

libvlc_media_release(media);
libvlc_media_player_play(mp);


snapshot from sout

const char *const vlc_args[] = {
"-I=dummy",
"--vout=dummy",
"--network-caching=5000",
  "--sout=#duplicate{dst=display,dst=rtp{sdp=rtsp://:8554/ch1}}", "--sout-all", "--sout-keep",  "--verbose=2",
"--file-logging", logFile,
};
int vlc_argc = sizeof(vlc_args) / sizeof(vlc_args[0]);
vlcInstance = libvlc_new(vlc_argc, vlc_args);
const char *psz_mrl = "rtsp://169.254.1.168:554/live2.sdp";
media = libvlc_media_new_location(vlcInstance, psz_mrl);
mp = libvlc_media_player_new_from_media(media);
libvlc_media_release(media);
libvlc_media_player_play(mp);

snapshot 需要 input_resource_t, 所以重點是傳遞 input_resource_t 的位址
vi ../modules/stream_out/display.c
    p_sys->p_resource = input_resource_New( p_this );
    var_Create(p_stream, "sout-display-input-resource", VLC_VAR_ADDRESS);
    var_SetAddress(p_stream, "sout-display-input-resource", p_sys->p_resource);
    msg_Dbg(p_stream, "display.Open set input_resource_t(%p) to sout_stream_t SSS", p_sys->p_resource);

將 input_resource_t 的位址,從 sout_stream_t 傳到 sout_instance_t
vi ../src/stream_output/stream_output.c
static sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_name,
                               config_chain_t *p_cfg, sout_stream_t *p_next)
{
    p_stream->p_module =
        module_need( p_stream, "sout stream", p_stream->psz_name, true );
    input_resource_t *p_resource = var_GetAddress(p_stream, "sout-display-input-resource");
    if (p_resource != NULL) {
        var_Create(p_sout, "sout-display-input-resource", VLC_VAR_ADDRESS);
        var_SetAddress(p_sout, "sout-display-input-resource", p_resource);
        msg_Dbg(p_sout, "stream_output:sout_StreamNew set input_resource_t(%p) from sout_stream_t to sout_instance_t SSS", p_resource);
    }
}

將 input_resource_t 的位址,從 sout_instance_t 傳到 input_thread_t
vi ../src/input/input.c
static int Init( input_thread_t * p_input )
{
    if (p_input->p->p_sout) {
        input_resource_t *p_resource = var_GetAddress(p_input->p->p_sout, "sout-display-input-resource");
        if (p_resource != NULL) {
            var_Create(p_input, "sout-display-input-resource", VLC_VAR_ADDRESS);
            var_SetAddress(p_input, "sout-display-input-resource", p_resource);
            msg_Dbg(p_input, "input.Init send input_resource_t(%p) from input_thread_t->p->p_sout to input_thread_t SSS", p_resource);
        }
    }
}

snapshot 是利用 vout_thread_t
vi ../lib/video.c
int libvlc_video_take_snapshot( libvlc_media_player_t *p_mi, unsigned num,
                            const char *psz_filepath,
                            unsigned int i_width, unsigned int i_height )
{
    vout_thread_t *p_vout = GetVout (p_mi, num);
}
GetVout -> GetVouts -> input_Control(INPUT_GET_VOUTS) -> input_vaControl

利用 input_resource_HoldVouts, 取得 vout_thread_t
vi ../src/input/control.c
int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
{
        case INPUT_GET_VOUTS:
        {
            vout_thread_t ***ppp_vout = (vout_thread_t***)va_arg( args, vout_thread_t*** );
            size_t        *pi_vout = va_arg( args, size_t * );

            input_resource_HoldVouts( p_input->p->p_resource, ppp_vout, pi_vout );
            if( *pi_vout <= 0 ) { // 找不到,更換另一個 input_resource_t
                input_resource_t *p_resource = var_GetAddress(p_input, "sout-display-input-resource");
                msg_Dbg(p_input, "control.input_vaControl input_resource_HoldVouts(sout-display-input-resource) SSS");
                input_resource_HoldVouts(p_resource, ppp_vout, pi_vout);
            }
            if( *pi_vout <= 0 ) {
                return VLC_EGENERIC;
            }
            return VLC_SUCCESS;
        }
}

2016年5月2日 星期一

顯示 rtsp, 含 vlc-log.txt

CStringA logFile = "--logfile=vlc-log-" + GetTimeString() + ".txt";
const char *const vlc_args[] = {
"-I=dummy",
"--network-caching=5000",
"--sub-source=marq{marquee=%Y/%m/%d %H:%M:%S.%l,x=10,y=50}",
"--verbose=2",
"--file-logging", logFile,
};
vlcInstance = libvlc_new(vlc_argc, vlc_args);
const char *psz_mrl = "rtsp://169.254.1.168:554/live2.sdp";
media = libvlc_media_new_location(vlcInstance, psz_mrl);
mp = libvlc_media_player_new_from_media(media);
libvlc_media_player_set_hwnd(mp, GetDlgItem(IDC_VIEWER)->m_hWnd);

libvlc_media_release(media);
libvlc_media_player_play(mp);

vlc-log.txt