MP4Demuxer.cpp 9.05 KB
Newer Older
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
xiongziliang committed
3
 *
4
 * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
xiongziliang committed
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.
xiongziliang committed
9 10 11 12 13 14 15 16
 */

#ifdef ENABLE_MP4
#include "MP4Demuxer.h"
#include "Util/logger.h"
#include "Extension/H265.h"
#include "Extension/H264.h"
#include "Extension/AAC.h"
17
#include "Extension/G711.h"
18
#include "Extension/Opus.h"
xiongziliang committed
19 20 21
using namespace toolkit;
namespace mediakit {

22
MP4Demuxer::MP4Demuxer() {}
xiongziliang committed
23 24 25 26 27 28

MP4Demuxer::~MP4Demuxer() {
    _mov_reader = nullptr;
    closeFile();
}

29 30 31 32 33 34 35
void MP4Demuxer::openMP4(const string &file){
    openFile(file.data(),"rb+");
    _mov_reader = createReader();
    getAllTracks();
    _duration_ms = mov_reader_getduration(_mov_reader.get());
}

xiongziliang committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
int MP4Demuxer::getAllTracks() {
    static mov_reader_trackinfo_t s_on_track = {
            [](void *param, uint32_t track, uint8_t object, int width, int height, const void *extra, size_t bytes) {
                //onvideo
                MP4Demuxer *thiz = (MP4Demuxer *)param;
                thiz->onVideoTrack(track,object,width,height,extra,bytes);
            },
            [](void *param, uint32_t track, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void *extra, size_t bytes) {
                //onaudio
                MP4Demuxer *thiz = (MP4Demuxer *)param;
                thiz->onAudioTrack(track,object,channel_count,bit_per_sample,sample_rate,extra,bytes);
            },
            [](void *param, uint32_t track, uint8_t object, const void *extra, size_t bytes) {
                //onsubtitle, do nothing
            }
    };
    return mov_reader_getinfo(_mov_reader.get(),&s_on_track,this);
}

#define SWITCH_CASE(obj_id) case obj_id : return #obj_id
static const char *getObjectName(int obj_id) {
    switch (obj_id) {
        SWITCH_CASE(MOV_OBJECT_TEXT);
        SWITCH_CASE(MOV_OBJECT_MP4V);
        SWITCH_CASE(MOV_OBJECT_H264);
        SWITCH_CASE(MOV_OBJECT_HEVC);
        SWITCH_CASE(MOV_OBJECT_AAC);
        SWITCH_CASE(MOV_OBJECT_MP2V);
        SWITCH_CASE(MOV_OBJECT_AAC_MAIN);
        SWITCH_CASE(MOV_OBJECT_AAC_LOW);
        SWITCH_CASE(MOV_OBJECT_AAC_SSR);
        SWITCH_CASE(MOV_OBJECT_MP3);
        SWITCH_CASE(MOV_OBJECT_MP1V);
        SWITCH_CASE(MOV_OBJECT_MP1A);
        SWITCH_CASE(MOV_OBJECT_JPEG);
        SWITCH_CASE(MOV_OBJECT_PNG);
        SWITCH_CASE(MOV_OBJECT_JPEG2000);
        SWITCH_CASE(MOV_OBJECT_G719);
        SWITCH_CASE(MOV_OBJECT_OPUS);
        SWITCH_CASE(MOV_OBJECT_G711a);
        SWITCH_CASE(MOV_OBJECT_G711u);
        SWITCH_CASE(MOV_OBJECT_AV1);
        default:
            return "unknown mp4 object";
    }
}


void MP4Demuxer::onVideoTrack(uint32_t track, uint8_t object, int width, int height, const void *extra, size_t bytes) {
    switch (object) {
        case MOV_OBJECT_H264: {
            auto video = std::make_shared<H264Track>();
            _track_to_codec.emplace(track,video);

            struct mpeg4_avc_t avc = {0};
            if (mpeg4_avc_decoder_configuration_record_load((uint8_t *) extra, bytes, &avc) > 0) {
                uint8_t config[1024] = {0};
                int size = mpeg4_avc_to_nalu(&avc, config, sizeof(config));
                if (size > 0) {
xiongziliang committed
95
                    video->inputFrame(std::make_shared<H264FrameNoCacheAble>((char *)config, size, 0, 4));
xiongziliang committed
96 97 98 99 100 101 102 103 104 105 106 107 108
                }
            }
        }
            break;
        case MOV_OBJECT_HEVC: {
            auto video = std::make_shared<H265Track>();
            _track_to_codec.emplace(track,video);

            struct mpeg4_hevc_t hevc = {0};
            if (mpeg4_hevc_decoder_configuration_record_load((uint8_t *) extra, bytes, &hevc) > 0) {
                uint8_t config[1024] = {0};
                int size = mpeg4_hevc_to_nalu(&hevc, config, sizeof(config));
                if (size > 0) {
xiongziliang committed
109
                    video->inputFrame(std::make_shared<H265FrameNoCacheAble>((char *) config, size, 0, 4));
xiongziliang committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
                }
            }
        }
            break;
        default:
            WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object);
            break;
    }
}

void MP4Demuxer::onAudioTrack(uint32_t track_id, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void *extra, size_t bytes) {
    switch(object){
        case MOV_OBJECT_AAC:{
            auto audio = std::make_shared<AACTrack>(bytes > 0 ? string((char *)extra,bytes) : "");
            _track_to_codec.emplace(track_id, audio);
            break;
126 127
        }

128 129 130 131
        case MOV_OBJECT_G711a:
        case MOV_OBJECT_G711u:{
            auto audio = std::make_shared<G711Track>(object == MOV_OBJECT_G711a ? CodecG711A : CodecG711U, sample_rate, channel_count, bit_per_sample / channel_count );
            _track_to_codec.emplace(track_id, audio);
132
            break;
133
        }
134 135 136 137

        case MOV_OBJECT_OPUS: {
            auto audio = std::make_shared<OpusTrack>();
            _track_to_codec.emplace(track_id, audio);
138
            break;
139 140
        }

xiongziliang committed
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
        default:
            WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object);
            break;
    }
}

int64_t MP4Demuxer::seekTo(int64_t stamp_ms) {
    if(0 != mov_reader_seek(_mov_reader.get(),&stamp_ms)){
        return -1;
    }
    return stamp_ms;
}

struct Context{
    MP4Demuxer *thiz;
    int flags;
    int64_t pts;
    int64_t dts;
    uint32_t track_id;
    BufferRaw::Ptr buffer;
};

163 164
#define DATA_OFFSET ADTS_HEADER_LEN

165 166 167
Frame::Ptr MP4Demuxer::readFrame(bool &keyFrame, bool &eof) {
    keyFrame = false;
    eof = false;
xiongziliang committed
168 169 170 171 172 173 174 175 176 177 178
    static mov_reader_onread mov_reader_onread = [](void *param, uint32_t track_id, const void *buffer, size_t bytes, int64_t pts, int64_t dts, int flags) {
        Context *ctx = (Context *) param;
        ctx->pts = pts;
        ctx->dts = dts;
        ctx->flags = flags;
        ctx->track_id = track_id;
    };

    static mov_onalloc mov_onalloc = [](void *param, int bytes) -> void * {
        Context *ctx = (Context *) param;
        ctx->buffer = ctx->thiz->_buffer_pool.obtain();
179 180 181
        ctx->buffer->setCapacity(bytes + DATA_OFFSET + 1);
        ctx->buffer->setSize(bytes + DATA_OFFSET);
        return ctx->buffer->data() + DATA_OFFSET;
xiongziliang committed
182 183 184 185 186
    };

    Context ctx = {this, 0};
    auto ret = mov_reader_read2(_mov_reader.get(), mov_onalloc, mov_reader_onread, &ctx);
    switch (ret) {
187 188
        case 0 : {
            eof = true;
xiongziliang committed
189
            return nullptr;
190
        }
xiongziliang committed
191 192

        case 1 : {
193
            keyFrame = ctx.flags & MOV_AV_FLAG_KEYFREAME;
xiongziliang committed
194
            return makeFrame(ctx.track_id, ctx.buffer, ctx.pts, ctx.dts);
xiongziliang committed
195 196
        }

197 198
        default : {
            eof = true;
xiongziliang committed
199
            WarnL << "读取mp4文件数据失败:" << ret;
xiongziliang committed
200
            return nullptr;
201
        }
xiongziliang committed
202 203 204 205 206 207 208 209
    }
}

Frame::Ptr MP4Demuxer::makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int64_t pts, int64_t dts) {
    auto it = _track_to_codec.find(track_id);
    if (it == _track_to_codec.end()) {
        return nullptr;
    }
210 211
    auto bytes = buf->size() - DATA_OFFSET;
    auto data = buf->data() + DATA_OFFSET;
xiongziliang committed
212 213 214 215
    auto codec = it->second->getCodecId();
    switch (codec) {
        case CodecH264 :
        case CodecH265 : {
216 217 218 219 220 221
            uint32_t offset = 0;
            while (offset < bytes) {
                uint32_t frame_len;
                memcpy(&frame_len, data + offset, 4);
                frame_len = ntohl(frame_len);
                if (frame_len + offset + 4 > bytes) {
xiongziliang committed
222 223
                    return nullptr;
                }
224 225
                memcpy(data + offset, "\x0\x0\x0\x1", 4);
                offset += (frame_len + 4);
xiongziliang committed
226 227
            }
            if (codec == CodecH264) {
228
                return std::make_shared<FrameWrapper<H264FrameNoCacheAble> >(buf, (uint32_t)dts, (uint32_t)pts, 4, DATA_OFFSET);
xiongziliang committed
229
            }
230
            return std::make_shared<FrameWrapper<H265FrameNoCacheAble> >(buf, (uint32_t)dts, (uint32_t)pts, 4, DATA_OFFSET);
231 232 233 234 235 236 237
        }

        case CodecAAC: {
            AACTrack::Ptr track = dynamic_pointer_cast<AACTrack>(it->second);
            assert(track);
            //加上adts头
            dumpAacConfig(track->getAacCfg(), buf->size() - DATA_OFFSET, (uint8_t *) buf->data() + (DATA_OFFSET - ADTS_HEADER_LEN), ADTS_HEADER_LEN);
238
            return std::make_shared<FrameWrapper<FrameFromPtr> >(buf, (uint32_t)dts, (uint32_t)pts, ADTS_HEADER_LEN, DATA_OFFSET - ADTS_HEADER_LEN, codec);
xiongziliang committed
239
        }
240

241
        case CodecOpus:
242 243
        case CodecG711A:
        case CodecG711U: {
244
            return std::make_shared<FrameWrapper<FrameFromPtr> >(buf, (uint32_t)dts, (uint32_t)pts, 0, DATA_OFFSET, codec);
245
        }
246 247

        default: return nullptr;
xiongziliang committed
248 249 250 251 252 253 254 255 256 257 258
    }
}

vector<Track::Ptr> MP4Demuxer::getTracks(bool trackReady) const {
    vector<Track::Ptr> ret;
    for (auto &pr : _track_to_codec) {
        if(trackReady && !pr.second->ready()){
            continue;
        }
        ret.push_back(pr.second);
    }
259
    return ret;
xiongziliang committed
260 261 262 263 264 265 266 267
}

uint64_t MP4Demuxer::getDurationMS() const {
    return _duration_ms;
}

}//namespace mediakit
#endif// ENABLE_MP4