⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msdl.c

📁 linux下流媒体下载程序代码
💻 C
📖 第 1 页 / 共 2 页
字号:
static int download_target(char *target_str,struct options_t *options,struct dlresult_t *result,			   char **local_name){    struct url_t *url = NULL;                 /* for each target url   */        struct download_opts_t *dlopts = NULL;    int ret = 0;    ret = prepare_download(target_str, options, 			   &url,&dlopts,			   local_name);       /* local filename will be determined */    if(!ret) {	goto failed;    }        ret = do_download(*local_name,url,dlopts);        if(ret > 0) {             /* succeeded */	list_h_append(&result->success_list,strdup(target_str));    }    else if(ret < 0) {        /* failed    */	list_h_append(&result->failed_list,strdup(target_str));    }    else {	/* ret == 0 which is NO_NEED_TO_DOWNLOAD */	/* it's not download success but of course not failure */	/* do nothing  and 0 will be returned */    }        if(url)             free_url_t(url);    if(dlopts)          free_download_opts_t(dlopts);    return ret;  failed:    if(url)             free_url_t(url);    if(dlopts)          free_download_opts_t(dlopts);    return -1;}/* * allocate url  and dlopts, from target_str and options * return value:  1 ... success  0 ... failure */static int prepare_download(char *target_str,struct options_t *options,			    struct url_t **url_ret,struct download_opts_t **dlopts_ret,			    char **local_name){    struct url_t *url = NULL;                 /* for each target url   */        struct download_opts_t *dlopts = NULL;        /*      check if target is really a file    */        url = new_url_t(target_str);    if(url == NULL) { /* invalid URL, just continue */	display(MSDL_VER,"ignored \"%s\"\n",target_str);	goto ignore;    }    /*     * check if target url is valid     */    if(!url->hostname || !strcmp(url->hostname,"")) {	display(MSDL_NOR,"ignored \"%s\" (no host information)\n",target_str);	goto ignore;    }    else if(!url->filepath || !strcmp(url->filepath,"")) {	display(MSDL_NOR,"warning: \"%s\" (no filepath)\n",target_str);	*local_name = NULL;    }    else { /* normal case */	*local_name = create_local_file_name(target_str,options);    }        if((!*local_name) || !strcmp(*local_name,"")) {	*local_name = strdup(default_file_name_for_empty); /* allocate default file name */    }        dlopts = new_download_opts_t();    set_dlopts_from_options(options,dlopts);    dlopts->dl_protocol = url->protocol_type;    /*      if url starts with "http", try MMSH first, and fallback on HTTP.      also, if MMST and HTTP_PROXY specified, use http.    */    if(url->protocol_type == HTTP ||       (url->protocol_type == MMST && dlopts->http_proxy)) {	dlopts->dl_protocol = MMSH;    }    /*      if url starts with "mms", try rtsp because it's the standard.      pure mmst protocol is obsolate.    */    if(url->protocol_type == MMST) {	dlopts->dl_protocol = RTSP_WMS;    }        /*      choose protocol if specified    */    if(options->protocol) {	dlopts->dl_protocol = protocol_type_from_string(options->protocol);	if(dlopts->dl_protocol == UNKNOWN_PROTOCOL) {	    display(MSDL_ERR,"protocol [ %s ] not supported: ignore this option \n",		    options->protocol);	    dlopts->dl_protocol = url->protocol_type;	}    }        *url_ret = url;    *dlopts_ret = dlopts;    return 1;  ignore:    if(url)      free_url_t(url);    if(dlopts)   free_download_opts_t(dlopts);    *url_ret = NULL;    *dlopts_ret = NULL;    return 0;}/* * do actual download * streaming_download() wrapper * return value:   what streaming_download returns  * ((CAUTION)) * streaming_download will return 0 if no need for downloading, and * in metafile case, it should be continue */static int do_download(const char *local_name,struct url_t *url,struct download_opts_t *dlopts){    int ret = 0;    int retry_again = 0;        /*      display download file name    */    display(MSDL_NOR,"download [ %s ]\n",local_name);    display(MSDL_VER,"url: %s\n",url->url);        /*      download file    */    do {	retry_again = 0;	ret = streaming_download(local_name,url,dlopts);		if((ret == -2) && (dlopts->auto_retry > 0)) {	    display(MSDL_NOR,"*** try again downloading (%d)\n",dlopts->auto_retry);	    dlopts->resume_download = 1; /* set resume enable */	    dlopts->auto_retry--;	    retry_again = 1;	}	    } while(retry_again);        return ret;}/* * print protocol name to screen. */static void display_protocol(struct stream_t *stream){    display(MSDL_VER,"download protocol: ");    switch (stream->stream_ctrl->protocol) {    case MMST:	display(MSDL_VER,"mmst");	break;    case MMSH:	display(MSDL_VER,"mmsh");	break;    case RTSP_REAL:	display(MSDL_VER,"rtsp - real");	break;    case RTSP_WMS:	display(MSDL_VER,"rtsp - wms");	break;    case HTTP:	display(MSDL_VER,"http");	break;    case FTP:	display(MSDL_VER,"ftp");	break;    default:	display(MSDL_ERR," :) ...bug");	break;    }      display(MSDL_VER,"\n\n");}struct stream_t *streaming_init(struct url_t *url,struct download_opts_t *dlopts){    struct stream_t *stream = NULL;    switch(dlopts->dl_protocol) {    case MMST:	stream = mmst_streaming_init();	break;    case HTTP:	stream = http_streaming_init();	break;    case MMSH:	stream = mmsh_streaming_init();	break;    case FTP:	stream = ftp_streaming_init();	break;    case RTSP:    case RTSP_WMS:    case RTSP_REAL:	stream = rtsp_streaming_init();	break;    default:	display(MSDL_ERR,"protocol [ %s:// ] not supported\n",url->protocol);	return NULL;    }	    stream->url = url;    stream->dlopts = dlopts;    return stream;}/* * main downloading function. * select DLing function according to url->protocol. * download 'url' to 'localfile' * *      return value;   1 ... succeeded *                      0 ... did nothing,  failure don't count *                     -1 ... failed *                     -2 ... failed while downloading, which means *                            protocol negotiation succeeded *                            thus, can retry later */int streaming_download(const char *local_file,struct url_t *url,struct download_opts_t *dlopts){    int ret = 0;    struct stream_t *stream = NULL;    int retries = 0;    FILE *fp = NULL;	    uint8_t *buffer = NULL;	        /*      download header.    */    for(retries = 2 ; retries > 0 ; retries--) {	stream = streaming_init(url,dlopts);	if(stream == NULL) {	    goto failed;	}		stream->localfile = strdup(local_file);	/*	  protocol initiation	*/	ret = stream->start(stream);		if(ret > 0) {	    /* success */	    break;	}	else if(stream->stream_ctrl->status == STREAMING_OTHER_PROTOCOL) {	    /* retry required (maximum chance is 'retries' times) */	    dlopts->dl_protocol = stream->stream_ctrl->retry_protocol;	    	    stream->close(stream); /* close stream for this protocol */	    stream = NULL;	    continue;	}	else if(stream->stream_ctrl->status == STREAMING_NO_NEED_TO_DOWNLOAD) {	    display(MSDL_NOR,"file \"%s\" already complete: not downloading\n",		    stream->localfile);	    goto already_done;	}	else if(stream->stream_ctrl->status == STREAMING_REDIRECTED) {	    if(stream->stream_ctrl->retry_urlstr) {		struct url_t *newurl = new_url_t(stream->stream_ctrl->retry_urlstr);		if(!newurl) {		    display(MSDL_ERR,"invalid redirection url %s",stream->stream_ctrl->retry_urlstr);		    goto failed;		}		else {		    char *p = strrchr(stream->stream_ctrl->retry_urlstr,'/');		    if(!p || p[1] == '\0') { /* not found , or "/" */			free(stream->localfile);			stream->localfile = strdup(local_file); /* copy the 'before redirection' filename */					    }		    else { /* filename found */			free(stream->localfile);			stream->localfile = strdup(p+1);        /* set new filename                       */		    }		    /* reset url members to new one */		    copy_url_t(url,newurl);		    free_url_t(newurl);		    		    stream->close(stream);		    stream = NULL;		    continue;		}	    }	    else {		display(MSDL_ERR,"stream_ctrl->retry_urlstr not set\n");		goto failed;	    }	}	else {	    /* protocol initiation error */	    display(MSDL_ERR,"cannot establish stream\n");	    goto failed;	}    }      if(retries <= 0) {	display(MSDL_ERR,"no more retry chance\n");	goto failed;    }    else { /* success */	uint64_t size_written = 0;         /* size written to file (current offset of file) */	uint64_t real_downloaded_size = 0; /* bytes got from network                        */	struct progressinfo_t pgi;	int resume_seek_ok = 0;	/* success initialize */	/*	 * display download protocol.	 * -- IMPORTANT --	 * this may differ from dlotps->dl_protocol or url->protocol_type,	 * as those are just request. there might be fallbacks or retries.	 */	display_protocol(stream);	/*	  download media.	*/	resume_seek_ok = 0;	if(stream->resumeinfo->resume_req_success) {	    if((fp = fopen(stream->localfile,"r+b")) == NULL) { /* append open */		display(MSDL_ERR,"error: open existing file \"%s\"\n",			stream->localfile);		perror("");		resume_seek_ok = 0;	    }	    else {		if(fseek(fp,stream->resumeinfo->resume_start_offset,SEEK_SET) < 0) {		    display(MSDL_ERR,"error: cannot seek \"%s\" to [%x]\n",			    stream->localfile,stream->resumeinfo->resume_start_offset);		    perror("");		    resume_seek_ok = 0;		    fclose(fp); /* close file */		}		else { /* success */		    display(MSDL_NOR,"resume: seek OK, start writing from %lld [0x%x]\n",			    stream->resumeinfo->resume_start_offset,			    stream->resumeinfo->resume_start_offset);				    stream->stream_ctrl->status = STREAMING_RESUME_BUFFERING;		    progress_dl_start(&pgi);		    pgi.last_speed_size_written = stream->resumeinfo->resume_start_offset;		    pgi.last_etl_speed_size_written = stream->resumeinfo->resume_start_offset;		    size_written = stream->resumeinfo->resume_start_offset;				    resume_seek_ok = 1;		}	    }	}    	if(!resume_seek_ok) {  /* not resuming --> just open normally */	    /* create file here */	    if((fp = fopen(stream->localfile,"wb")) ==  NULL) {		display(MSDL_ERR,"cannot create file \"%s\"\n",stream->localfile);		perror("");		goto failed;	    }	    progress_dl_start(&pgi);		}    	buffer = (uint8_t *)xmalloc(BUFSIZE_4_DL);	real_downloaded_size = 0;	for(;;) {    	    if((stream->stream_ctrl->write_data_len < BUFSIZE_4_DL) &&   /* write queue not enough  */	       stream_check_data(stream,STREAM_CHECK_DATA_TIME) <= 0) {  /* nothing to read         */		/* some error or data didn't come within few(default 5) seconds*/		display_progress_info(stream->stream_ctrl->file_size,size_written,0,0);	    }		    ret = stream->read(stream,buffer,BUFSIZE_4_DL);		    /* 	       write received packet directory to file.	       everything, such as padding has been done alrady, just write it.	    */		    if(ret > 0) { /* success */	    		if(stream->stream_ctrl->status == STREAMING_REWIND) {		    /*		      have to write data AFTER deleting all current file content.		    */		    display(MSDL_VER,"rewind file!!\n");		    rewind(fp);		    size_written = 0;		    real_downloaded_size = 0;		    stream->stream_ctrl->packet_count = 0;		    stream->stream_ctrl->status = STREAMING_DOWNLOADING;		    /* cont as download restart */		    progress_dl_start(&pgi);		}	    		size_written += ret;		real_downloaded_size += ret;		progress_update(&pgi,stream->stream_ctrl->file_size,size_written);		/*		  display(MSDL_DBG,"\npacket count: %d\n",stream->stream_ctrl->packet_count);		  display(MSDL_DBG,"ftell: %d [%x] --> write %d [%x]\n",ftell(fp),ftell(fp),ret,ret);		*/		ret = fwrite(buffer,sizeof(uint8_t),ret,fp);	    }	    else if(stream->stream_ctrl->status == STREAMING_RESUME_BUFFERING) {		/*		 * just do nothing, stream->read will automatically seek to THAT position,		 * and remove STREAMING_RESUME_BUFFERING.		 */		display_progress_info(stream->stream_ctrl->file_size,size_written,-1,-1);		continue;	    }	    else if(stream->stream_ctrl->status == STREAMING_FINISHED) {		/*		  show 100%, because 99% sucks ...		  have to do this because stream->stream_ctrl->file_size		  may show wrong file size.		*/		int64_t average_speed = progress_get_average_bandwidth(&pgi,real_downloaded_size);	    		display_progress_info(size_written,size_written,average_speed,0);		display(MSDL_NOR,"\nfinished!!\n");		break;	    }	    /*	      return value is 0 if failure	    */	    else { /* error while download */		display(MSDL_ERR,"!!! aborted by error !!!\n");		goto failed_while_downloading;	    }	}      }        display(MSDL_NOR,"\n");    if(stream) stream->close(stream);    if(buffer) free(buffer);    fclose(fp);    return 1;  already_done:    display(MSDL_NOR,"\n");    if(stream) stream->close(stream);    if(buffer) free(buffer);    if(fp)     fclose(fp);    return 0;  failed:    display(MSDL_NOR,"\n");    if(stream) stream->close(stream);    if(buffer) free(buffer);    if(fp)     fclose(fp);    return -1;  failed_while_downloading: /* --> can retry later */    display(MSDL_NOR,"\n");    if(stream) stream->close(stream);    if(buffer) free(buffer);    if(fp)     fclose(fp);    return -2;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -