HlsMakerImp.cpp 4.34 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
3
 *
4
 * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
5
 *
xiongziliang committed
6 7 8
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
9 10
 */

11 12
#include <ctime>
#include <sys/stat.h>
13 14 15
#include "HlsMakerImp.h"
#include "Util/util.h"
#include "Util/uv_errno.h"
16

17 18 19 20 21 22 23 24 25 26 27 28 29
using namespace toolkit;

namespace mediakit {

HlsMakerImp::HlsMakerImp(const string &m3u8_file,
                         const string &params,
                         uint32_t bufSize,
                         float seg_duration,
                         uint32_t seg_number) : HlsMaker(seg_duration, seg_number) {
    _path_prefix = m3u8_file.substr(0, m3u8_file.rfind('/'));
    _path_hls = m3u8_file;
    _params = params;
    _buf_size = bufSize;
30
    _file_buf.reset(new char[bufSize], [](char *ptr) {
31 32
        delete[] ptr;
    });
33

34
    _info.folder = _path_prefix;
35 36 37
}

HlsMakerImp::~HlsMakerImp() {
38 39 40 41
    clearCache();
}

void HlsMakerImp::clearCache() {
xiongziliang committed
42
    //录制完了
xiongziliang committed
43
    flushLastSegment(true);
44
    if (isLive()) {
xiongziliang committed
45
        //hls直播才删除文件
46 47 48
        clear();
        _file = nullptr;
        _segment_file_paths.clear();
xiongziliang committed
49 50
        File::delete_file(_path_prefix.data());
    }
51 52
}

53
string HlsMakerImp::onOpenSegment(uint64_t index) {
54
    string segment_name, segment_path;
55 56
    {
        auto strDate = getTimeStr("%Y-%m-%d");
57 58 59
        auto strHour = getTimeStr("%H");
        auto strTime = getTimeStr("%M-%S");
        segment_name = StrPrinter << strDate + "/" + strHour + "/" + strTime << "_" << index << ".ts";
60 61 62
        segment_path = _path_prefix + "/" + segment_name;
        if (isLive()) {
            _segment_file_paths.emplace(index, segment_path);
xiongziliang committed
63
        }
64 65
    }
    _file = makeFile(segment_path, true);
66

67 68 69 70 71
    //保存本切片的元数据
    _info.start_time = ::time(NULL);
    _info.file_name = segment_name;
    _info.file_path = segment_path;
    _info.url = _info.app + "/" + _info.stream + "/" + segment_name;
72

73 74
    if (!_file) {
        WarnL << "create file failed," << segment_path << " " << get_uv_errmsg();
75
    }
76
    if (_params.empty()) {
77
        return segment_name;
78
    }
79
    return segment_name + "?" + _params;
80 81
}

82
void HlsMakerImp::onDelSegment(uint64_t index) {
83
    auto it = _segment_file_paths.find(index);
84
    if (it == _segment_file_paths.end()) {
85 86 87 88
        return;
    }
    File::delete_file(it->second.data());
    _segment_file_paths.erase(it);
89 90
}

91
void HlsMakerImp::onWriteSegment(const char *data, size_t len) {
92 93 94
    if (_file) {
        fwrite(data, len, 1, _file.get());
    }
95 96 97
    if (_media_src) {
        _media_src->onSegmentSize(len);
    }
98 99
}

100
void HlsMakerImp::onWriteHls(const char *data, size_t len) {
101
    auto hls = makeFile(_path_hls);
102 103
    if (hls) {
        fwrite(data, len, 1, hls.get());
104
        hls.reset();
105
        if (_media_src) {
106
            _media_src->registHls(true);
107
        }
108 109
    } else {
        WarnL << "create hls file failed," << _path_hls << " " << get_uv_errmsg();
110 111 112 113
    }
    //DebugL << "\r\n"  << string(data,len);
}

114
void HlsMakerImp::onFlushLastSegment(uint32_t duration_ms) {
115 116
    GET_CONFIG(bool, broadcastRecordTs, Hls::kBroadcastRecordTs);
    if (broadcastRecordTs) {
117 118
        //关闭ts文件以便获取正确的文件大小
        _file = nullptr;
119
        _info.time_len = duration_ms / 1000.0f;
120 121 122 123
        struct stat fileData;
        stat(_info.file_path.data(), &fileData);
        _info.file_size = fileData.st_size;
        NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordTs, _info);
124
    }
125 126
}

127
std::shared_ptr<FILE> HlsMakerImp::makeFile(const string &file, bool setbuf) {
128
    auto file_buf = _file_buf;
129
    auto ret = shared_ptr<FILE>(File::create_file(file.data(), "wb"), [file_buf](FILE *fp) {
130 131 132 133
        if (fp) {
            fclose(fp);
        }
    });
134
    if (ret && setbuf) {
135 136 137 138 139
        setvbuf(ret.get(), _file_buf.get(), _IOFBF, _buf_size);
    }
    return ret;
}

140
void HlsMakerImp::setMediaSource(const string &vhost, const string &app, const string &stream_id) {
141
    _media_src = std::make_shared<HlsMediaSource>(vhost, app, stream_id);
142 143 144
    _info.app = app;
    _info.stream = stream_id;
    _info.vhost = vhost;
145 146
}

147
HlsMediaSource::Ptr HlsMakerImp::getMediaSource() const {
148 149 150
    return _media_src;
}

151
}//namespace mediakit