Search in sources :

Example 1 with TsSegment

use of com.feeyo.hls.ts.TsSegment in project feeyo-hlsserver by variflight.

the class HlsLiveHandler method execute.

@Override
public void execute(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    HttpRequest request = (DefaultHttpRequest) e.getMessage();
    String uri = request.getUri();
    String path = uri.split("[?]")[0].trim();
    String[] pathArray = path.split("/");
    String alias = pathArray[2];
    String requestFile = pathArray[3];
    // 校验 alias & requestFile
    if (alias == null || requestFile == null) {
        HttpUtil.sendError(ctx, HttpResponseStatus.NOT_FOUND);
        return;
    }
    // 根据 alias 获取 live
    HlsLiveStream liveStream = HlsLiveStreamMagr.INSTANCE().getHlsLiveStreamByAlias(alias);
    if (liveStream == null) {
        HttpUtil.sendError(ctx, HttpResponseStatus.NOT_FOUND);
        return;
    }
    // live.m3u8
    if (requestFile.equals(LIVE_M3U8)) {
        HlsClientSession clientSession = null;
        // 提取 sid
        QueryStringDecoder decoder = new QueryStringDecoder(request.getUri());
        List<String> sessionId = decoder.getParameters().get("sid");
        if (sessionId != null && !sessionId.isEmpty()) {
            clientSession = liveStream.getClientSessionsById(sessionId.get(0));
        }
        LOGGER.info("request m3u8 file,  uri={}, clientSession={}", uri, clientSession);
        // 重定向, 解决标识问题
        if (clientSession == null) {
            clientSession = liveStream.newClientSession();
            StringBuffer url = new StringBuffer(50);
            url.append(path).append("?sid=").append(clientSession.getId());
            LOGGER.info("response redirect, url={}", url.toString());
            HttpResponse response = HttpUtil.redirectFound(url.toString());
            e.getChannel().write(response);
            return;
        }
        M3U8 m3u8 = clientSession.getM3u8File(requestFile);
        DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
        byte[] content = m3u8.getBuf();
        long fileMTime = m3u8.getTime();
        response.headers().add(HttpHeaders.Names.SERVER, Versions.SERVER_VERSION);
        response.headers().add(HttpHeaders.Names.DATE, HttpUtil.getDateString(fileMTime));
        response.headers().add(HttpHeaders.Names.CONTENT_TYPE, HttpUtil.getMimeType(requestFile));
        response.headers().add(HttpHeaders.Names.CONTENT_LENGTH, content.length);
        // 
        response.headers().add(HttpHeaders.Names.CACHE_CONTROL, "private, max-age=5");
        response.setContent(ChannelBuffers.copiedBuffer(content));
        e.getChannel().write(response);
    // 1...N.ts
    } else {
        LOGGER.info("request ts file, uri={} ", uri);
        int tsIndex = Integer.valueOf(requestFile.substring(0, requestFile.indexOf(".ts"))).intValue();
        // 
        String ifModifiedSince = request.headers().get(HttpHeaders.Names.IF_MODIFIED_SINCE);
        if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) {
            SimpleDateFormat dateFormatter = new SimpleDateFormat(HttpUtil.HTTP_DATE_FORMAT, Locale.US);
            Date mdate = dateFormatter.parse(ifModifiedSince);
            int mdateSec = (int) (mdate.getTime() / 1000L);
            TsSegment tsSegment = liveStream.fetchTsSegment(tsIndex);
            int fileMTimeSec = tsSegment != null ? (int) (tsSegment.getCtime() / 1000L) : 0;
            if (mdateSec == fileMTimeSec) {
                HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_MODIFIED);
                response.headers().add(HttpHeaders.Names.CACHE_CONTROL, "max-age=1");
                HttpUtil.sendNotModified(ctx, response);
                return;
            }
        }
        TsSegment tsSegment = liveStream.fetchTsSegment(tsIndex);
        if (tsSegment == null) {
            HttpUtil.sendError(ctx, HttpResponseStatus.NOT_FOUND);
            return;
        }
        DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
        byte[] content = tsSegment.getData();
        long fileMTime = tsSegment.getCtime();
        response.headers().add(HttpHeaders.Names.SERVER, Versions.SERVER_VERSION);
        response.headers().add(HttpHeaders.Names.DATE, HttpUtil.getDateString(fileMTime));
        response.headers().add(HttpHeaders.Names.CONTENT_TYPE, HttpUtil.getMimeType(requestFile));
        response.headers().add(HttpHeaders.Names.CONTENT_LENGTH, content.length);
        response.headers().add(HttpHeaders.Names.LAST_MODIFIED, HttpUtil.getDateString(fileMTime));
        // 相对当前的过期时间,以分钟为单位
        response.headers().add(HttpHeaders.Names.EXPIRES, HttpUtil.getDateString(fileMTime + LIVE_CACHE_TIME));
        response.headers().add(HttpHeaders.Names.CACHE_CONTROL, "max-age=" + (LIVE_CACHE_TIME / 1000));
        response.setContent(ChannelBuffers.copiedBuffer(content));
        e.getChannel().write(response);
    }
}
Also used : HttpRequest(org.jboss.netty.handler.codec.http.HttpRequest) DefaultHttpRequest(org.jboss.netty.handler.codec.http.DefaultHttpRequest) HlsClientSession(com.feeyo.hls.HlsClientSession) DefaultHttpResponse(org.jboss.netty.handler.codec.http.DefaultHttpResponse) HttpResponse(org.jboss.netty.handler.codec.http.HttpResponse) M3U8(com.feeyo.hls.m3u8.M3U8) TsSegment(com.feeyo.hls.ts.TsSegment) Date(java.util.Date) QueryStringDecoder(org.jboss.netty.handler.codec.http.QueryStringDecoder) DefaultHttpRequest(org.jboss.netty.handler.codec.http.DefaultHttpRequest) DefaultHttpResponse(org.jboss.netty.handler.codec.http.DefaultHttpResponse) HlsLiveStream(com.feeyo.hls.HlsLiveStream) SimpleDateFormat(java.text.SimpleDateFormat)

Example 2 with TsSegment

use of com.feeyo.hls.ts.TsSegment in project feeyo-hlsserver by variflight.

the class HlsLiveStream method addAvStream.

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public synchronized void addAvStream(byte rawType, byte[] rawReserved, byte[] rawData, byte[] reserved) {
    this.mtime = System.currentTimeMillis();
    if (tsSegmenter != null) {
        byte[] tsData = tsSegmenter.getTsBuf(rawType, rawData, reserved);
        if (tsData != null) {
            long tsIndex = tsSegmentIndexGen.getAndIncrement();
            TsSegment tsSegment = new TsSegment(tsIndex + ".ts", tsData, tsSegmenter.getTsSegTime(), false);
            tsSegments.put(tsIndex, tsSegment);
            LOGGER.info("add ts {} ", tsSegment);
            try {
                _lock.writeLock().lock();
                if (tsSegmentIndexs.size() >= 5) {
                    tsSegmentIndexs.remove(0);
                }
                tsSegmentIndexs.add(tsIndex);
            } finally {
                _lock.writeLock().unlock();
            }
        }
    }
}
Also used : TsSegment(com.feeyo.hls.ts.TsSegment)

Example 3 with TsSegment

use of com.feeyo.hls.ts.TsSegment in project feeyo-hlsserver by variflight.

the class AdsMagr method initialize.

// 
public static void initialize() {
    String adsPath = HlsCtx.INSTANCE().getHomePath() + File.separator + "ads";
    File adsDirectory = new File(adsPath);
    if (adsDirectory.exists() && adsDirectory.isDirectory()) {
        List<AdsCfg> adsCfgs = HlsCtx.INSTANCE().getAdsCfgs();
        for (AdsCfg adsCfg : adsCfgs) {
            String md5 = Md5.md5_32(adsCfg.getType() + adsCfg.getSampleRate() + adsCfg.getSampleSizeInBits() + adsCfg.getChannels() + adsCfg.getFps());
            String filePath = adsPath + File.separator + adsCfg.getName();
            File file = new File(filePath);
            if (file.isFile() && file.exists()) {
                InputStream in = null;
                try {
                    in = new FileInputStream(file);
                    byte[] adRawData = new byte[(int) file.length()];
                    in.read(adRawData, 0, adRawData.length);
                    switch(adsCfg.getType()) {
                        case "audio":
                            AacTsSegmenter aacTsSegmenter = new AacTsSegmenter();
                            aacTsSegmenter.initialize(adsCfg.getSampleRate(), adsCfg.getSampleSizeInBits(), adsCfg.getChannels(), adsCfg.getFps());
                            // cache aac ts
                            if (adRawData != null) {
                                List<TsSegment> aacTsSegs = new ArrayList<TsSegment>();
                                aacTsSegmenter = new AacTsSegmenter();
                                // 3 : TS_PES_AU_NUM
                                aacTsSegmenter.setPts(aacTsSegmenter.getPtsIncPerFrame() * 3);
                                int rawDataPtr = 0;
                                int tsNum = aacTsSegmenter.calcTsNum(adRawData.length);
                                byte[] frameBuf = new byte[1024];
                                for (int i = 0; i < tsNum; i++) {
                                    if (rawDataPtr + frameBuf.length < adRawData.length) {
                                        System.arraycopy(adRawData, rawDataPtr, frameBuf, 0, frameBuf.length);
                                        rawDataPtr += frameBuf.length;
                                    } else if (rawDataPtr < adRawData.length) {
                                        Arrays.fill(frameBuf, (byte) 0);
                                        System.arraycopy(adRawData, rawDataPtr, frameBuf, 0, adRawData.length - rawDataPtr);
                                        rawDataPtr += frameBuf.length;
                                    } else {
                                        frameBuf = FaacUtils.ZERO_PCM_DATA;
                                    }
                                    byte[] tsSegment = aacTsSegmenter.getTsBuf(V5PacketType.AAC_STREAM, frameBuf, null);
                                    if (tsSegment != null) {
                                        aacTsSegs.add(new TsSegment((i + 1) + ".ts", tsSegment, aacTsSegmenter.getTsSegTime(), true));
                                    }
                                }
                                adsSegs.put(md5, aacTsSegs);
                            }
                            break;
                        case "video":
                            H264TsSegmenter h264TsSegmenter = new H264TsSegmenter();
                            h264TsSegmenter.initialize(adsCfg.getSampleRate(), adsCfg.getSampleSizeInBits(), adsCfg.getChannels(), adsCfg.getFps());
                            // cache h264 ts
                            if (adRawData != null) {
                                List<TsSegment> h264TsSegs = new ArrayList<TsSegment>();
                                h264TsSegmenter = new H264TsSegmenter();
                                int index = 0;
                                int ptr = 0;
                                while (ptr < adRawData.length) {
                                    int len = ptr + 2048 < adRawData.length ? 2048 : adRawData.length - ptr;
                                    byte[] dest = new byte[len];
                                    System.arraycopy(adRawData, ptr, dest, 0, len);
                                    byte[] tsSegment = h264TsSegmenter.getTsBuf(V5PacketType.H264_STREAM, dest, null);
                                    if (tsSegment != null)
                                        h264TsSegs.add(new TsSegment((++index) + ".ts", tsSegment, h264TsSegmenter.getTsSegTime(), true));
                                    ptr += 2048;
                                }
                                adsSegs.put(md5, h264TsSegs);
                            }
                            break;
                        case "mixed":
                            AacH264MixedTsSegmenter mixedTsSegmenter = new AacH264MixedTsSegmenter();
                            mixedTsSegmenter.initialize(adsCfg.getSampleRate(), adsCfg.getSampleSizeInBits(), adsCfg.getChannels(), adsCfg.getFps());
                            if (adRawData != null) {
                                List<TsSegment> mixedTsSegs = new ArrayList<TsSegment>();
                                // TODO segment
                                adsSegs.put(md5, mixedTsSegs);
                            }
                            break;
                        default:
                            continue;
                    }
                } catch (Exception e) {
                    LOGGER.error(e.getMessage());
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                        }
                    }
                }
            }
        }
    }
}
Also used : AacTsSegmenter(com.feeyo.hls.ts.segmenter.AacTsSegmenter) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) ArrayList(java.util.ArrayList) AacH264MixedTsSegmenter(com.feeyo.hls.ts.segmenter.AacH264MixedTsSegmenter) IOException(java.io.IOException) TsSegment(com.feeyo.hls.ts.TsSegment) H264TsSegmenter(com.feeyo.hls.ts.segmenter.H264TsSegmenter) FileInputStream(java.io.FileInputStream) IOException(java.io.IOException) AdsCfg(com.feeyo.cfg.AdsCfg) File(java.io.File)

Example 4 with TsSegment

use of com.feeyo.hls.ts.TsSegment in project feeyo-hlsserver by variflight.

the class HlsClientSession method getM3u8File.

public M3U8 getM3u8File(String filename) throws Exception {
    boolean isTsModified = false;
    if (ctime == mtime && AdsMagr.isHasAds()) {
        tsIndexs = new long[] { 1, 2, 3 };
    } else {
        long[] newTsIndexs = liveStream.fetchTsIndexs();
        if (tsIndexs != null && tsIndexs[0] < 4) {
            if (newTsIndexs != null && tsIndexs[tsIndexs.length - 1] < newTsIndexs[newTsIndexs.length - 1]) {
                for (int i = 0; i < tsIndexs.length - 1; i++) {
                    tsIndexs[i] = tsIndexs[i + 1];
                }
                if (tsIndexs.length < 5) {
                    tsIndexs = Arrays.copyOf(tsIndexs, 5);
                    tsIndexs[2] = newTsIndexs[newTsIndexs.length - 3];
                    tsIndexs[3] = newTsIndexs[newTsIndexs.length - 2];
                    tsIndexs[4] = newTsIndexs[newTsIndexs.length - 1];
                }
                tsIndexs[tsIndexs.length - 1] = newTsIndexs[newTsIndexs.length - 1];
                isTsModified = true;
            }
        } else if (tsIndexs == null && newTsIndexs != null) {
            tsIndexs = newTsIndexs;
            isTsModified = true;
        } else if (tsIndexs != null && newTsIndexs != null) {
            if (tsIndexs[tsIndexs.length - 1] < newTsIndexs[newTsIndexs.length - 1]) {
                // 后往前移
                for (int i = 0; i < tsIndexs.length - 1; i++) {
                    tsIndexs[i] = tsIndexs[i + 1];
                }
                tsIndexs[tsIndexs.length - 1] = tsIndexs[tsIndexs.length - 2] + 1;
                isTsModified = true;
            }
        }
    }
    this.mtime = System.currentTimeMillis();
    LOGGER.info("rquest filename={} " + ", tsIndexs=" + Arrays.toString(tsIndexs), filename);
    // 
    List<TsSegment> tsSegments = new LinkedList<TsSegment>();
    if (tsIndexs != null) {
        for (long tsIndex : tsIndexs) {
            TsSegment tsSegment = liveStream.fetchTsSegment(tsIndex);
            if (tsSegment != null) {
                if (tsSegment.isAds())
                    tsSegment.setDiscontinue(true);
                tsSegments.add(tsSegment);
            }
        }
    }
    long m3u8Seq = m3u8 == null ? 0 : m3u8.getSeq();
    m3u8Seq++;
    m3u8 = m3u8Builder.generateM3u8(isTsModified ? m3u8Seq++ : m3u8Seq, tsSegments);
    LOGGER.info("response m3u8, {}", m3u8);
    return m3u8;
}
Also used : TsSegment(com.feeyo.hls.ts.TsSegment) LinkedList(java.util.LinkedList)

Example 5 with TsSegment

use of com.feeyo.hls.ts.TsSegment in project feeyo-hlsserver by variflight.

the class HlsLiveStream method fetchTsSegment.

public TsSegment fetchTsSegment(long index) {
    if (index < 0)
        return null;
    TsSegment tsSegment = null;
    if (index < 4) {
        List<TsSegment> adTsSegments = adsMagr.getAdsTsSegments("audio", 8000F, 16, 1, 25);
        tsSegment = adTsSegments.get((int) index - 1);
    } else {
        tsSegment = tsSegments.get(index);
    }
    if (tsSegment != null) {
        tsSegment.setLasttime(System.currentTimeMillis());
    }
    return tsSegment;
}
Also used : TsSegment(com.feeyo.hls.ts.TsSegment)

Aggregations

TsSegment (com.feeyo.hls.ts.TsSegment)6 AdsCfg (com.feeyo.cfg.AdsCfg)1 HlsClientSession (com.feeyo.hls.HlsClientSession)1 HlsLiveStream (com.feeyo.hls.HlsLiveStream)1 M3U8 (com.feeyo.hls.m3u8.M3U8)1 AacH264MixedTsSegmenter (com.feeyo.hls.ts.segmenter.AacH264MixedTsSegmenter)1 AacTsSegmenter (com.feeyo.hls.ts.segmenter.AacTsSegmenter)1 H264TsSegmenter (com.feeyo.hls.ts.segmenter.H264TsSegmenter)1 File (java.io.File)1 FileInputStream (java.io.FileInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 SimpleDateFormat (java.text.SimpleDateFormat)1 ArrayList (java.util.ArrayList)1 Date (java.util.Date)1 LinkedList (java.util.LinkedList)1 DefaultHttpRequest (org.jboss.netty.handler.codec.http.DefaultHttpRequest)1 DefaultHttpResponse (org.jboss.netty.handler.codec.http.DefaultHttpResponse)1 HttpRequest (org.jboss.netty.handler.codec.http.HttpRequest)1 HttpResponse (org.jboss.netty.handler.codec.http.HttpResponse)1