HLS学习(七)HLSDownloader源码分析(6)下载TS文件片段

下载TS文件片段



处理完Master PlayList和Media PlayList之后就可以开始下载TS视频片段了


下载的流程如下:
1、初始化本地的文件名
2、设置本地文件的访问权限
3、创建任务队列
4、创建PlayList更新线程,因为服务器上的m3u8文件可能会经过改动,因此需要实时更新
5、遍历任务队列,队列里面存放的是TS媒体文件的信息,根据这些信息,下载TS视频文件。另外,如果下载的文件的大小已经超过了最大的文件的大小 ,那么表示服务器上的m3u8文件已经修改,需要更新PlayList


// 下载TS文件
int download_hls(struct hls_media_playlist *me,bool live_streamming,int max_file_size,const char* custom_filename, std::string user_agent, bool force_overwrite=true)
{
    if(live_streamming){
        MSG_VERBOSE("Downloading Live Streaming\n");
    }else{
        MSG_VERBOSE("Downloading %d segments.\n", me->count);
    }

    char filename[MAX_FILENAME_LEN];

	// 初始化本地文件名
    if (custom_filename!=NULL && *custom_filename!='\0') {
        strcpy(filename, custom_filename);
    } else {
        strcpy(filename, "000_hls_output.ts");
    }

	// 访问权限的设置
    if (access(filename, F_OK) != -1) {
        if (force_overwrite) {
            if (remove(filename) != 0) {
                MSG_ERROR("Error overwriting file");
                exit(1);
            }
        } else {
            char userchoice;
            MSG_PRINT("File already exists. Overwrite? (y/n) ");
            scanf("\n%c", &userchoice);
            if (userchoice == 'y') {
                if (remove(filename) != 0) {
                    MSG_ERROR("Error overwriting file");
                    exit(1);
                }
            } else {
                MSG_WARNING("Choose a different filename. Exiting.\n");
                exit(0);
            }
        }
    }

	// 创建任务队列
    std::shared_ptr<Queue<std::shared_ptr<hls_media_segment>>> segment_queue(new Queue<std::shared_ptr<hls_media_segment>>());
    std::mutex mutex_;
    std::condition_variable cond_;
    bool flag_finish=false;

    int lattest_sequence_number=-1;
	
	// 更新PlayList的线程,服务器上的m3u8文件可能更新得很频繁
    std::shared_ptr<std::thread> update_playlist_thread=std::make_shared<std::thread>([&]{    
        bool first_download_iteration = true;
        int wait_second= me->target_duration > 0 ?me->target_duration:1;
        while(first_download_iteration || live_streamming){
            {
                std::lock_guard<std::mutex> mlock(mutex_);
                if(flag_finish){
                    break;
                }
            }

            first_download_iteration = false;
            int i=0,current_file_count=0;
            
            for (; i < me->count&&me->media_segment[i].sequence_number <= lattest_sequence_number; i++);
            
            //Build downloading queue
            current_file_count = i;
            for (; i < me->count; i++) {
                //MSG_PRINT(me->media_segment[i].url); 
                segment_queue->push(std::make_shared<hls_media_segment>(me->media_segment[i]));
                lattest_sequence_number= me->media_segment[i].sequence_number;
            }


            MSG_PRINT("Update %d ts to queue\n",me->count - current_file_count);
            {
                std::unique_lock<std::mutex> mlock(mutex_);
                cond_.notify_one();
            }
            if(live_streamming){
                if(me->count - current_file_count < 1){    
                    
                    wait_second = wait_second*2;
                }else{
                    wait_second = me->target_duration;
                }
                MSG_PRINT("Sleep %d Seconds\n",wait_second);
                std::this_thread::sleep_for(std::chrono::seconds(wait_second));
                

                if (handle_hls_media_playlist(me,user_agent)) {
                    break;
                }
                MSG_PRINT("Reload m3u3 Playlist\n");
            }
        }
    });


    FILE *pFile = fopen(filename, "wb");
    int file_size=0;
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        cond_.wait(mlock,[segment_queue]()->bool{return !(segment_queue->empty());});
    }
    while(!segment_queue->empty()){
        auto segment=segment_queue->pop();

        MSG_PRINT("Thread %d Downloading segment %d\n", 0, segment->sequence_number);
        auto buffer = std::make_shared<ByteBuffer>();

		// 下载TS视频片段
        buffer->len = (int)get_data_from_url(segment->url.c_str(), NULL, &(buffer->data), BINARY,user_agent);
       
        if (me->encryption == true && me->encryptiontype == ENC_AES128) {
            decrypt_aes128(segment.get(), buffer.get());
        } else if (me->encryption == true && me->encryptiontype == ENC_AES_SAMPLE) {
            decrypt_sample_aes(segment.get(), buffer.get());
        }
		
		// 写入本地文件中
        fwrite(buffer->data, 1, buffer->len, pFile);
        fflush(pFile);
        free(buffer->data);
        file_size=file_size+buffer->len;
        MSG_PRINT("Totally Downloading Size: %d....Max size %d\n", file_size,max_file_size);
		
		// 如果下载的文件的大小已经超过了最大的文件大小,那么表示服务器上的PlayList可能已经更新了,本地应该及时更新
        if(max_file_size>0 && file_size >= max_file_size){
            std::lock_guard<std::mutex> mlock(mutex_);
            flag_finish = true; // 设置为true,那么更新线程就可以继续执行了
            MSG_PRINT("Reach Max Size %d! Finish.\n", max_file_size);
            break;
        }
        //delete segment;
    }


    fclose(pFile);
    update_playlist_thread->join();
    
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值