VideoSubscriber.java
3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
95
96
97
98
99
100
101
package cn.org.hentai.jtt1078.subscriber;
import cn.org.hentai.jtt1078.codec.MP3Encoder;
import cn.org.hentai.jtt1078.flv.AudioTag;
import cn.org.hentai.jtt1078.flv.FlvAudioTagEncoder;
import cn.org.hentai.jtt1078.flv.FlvEncoder;
import cn.org.hentai.jtt1078.util.ByteBufUtils;
import cn.org.hentai.jtt1078.util.FLVUtils;
import cn.org.hentai.jtt1078.util.HttpChunk;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
/**
* Created by matrixy on 2020/1/13.
*/
public class VideoSubscriber extends Subscriber
{
private long videoTimestamp = 0;
private long audioTimestamp = 0;
private long lastVideoFrameTimeOffset = 0;
private long lastAudioFrameTimeOffset = 0;
private boolean videoHeaderSent = false;
public VideoSubscriber(String tag, ChannelHandlerContext ctx)
{
super(tag, ctx);
}
@Override
public void onVideoData(long timeoffset, byte[] data, FlvEncoder flvEncoder)
{
if (lastVideoFrameTimeOffset == 0) lastVideoFrameTimeOffset = timeoffset;
// 之前是不是已经发送过了?没有的话,需要补发FLV HEADER的。。。
if (videoHeaderSent == false && flvEncoder.videoReady())
{
enqueue(HttpChunk.make(flvEncoder.getHeader().getBytes()));
enqueue(HttpChunk.make(flvEncoder.getVideoHeader().getBytes()));
// 直接下发第一个I帧
byte[] iFrame = flvEncoder.getLastIFrame();
if (iFrame != null)
{
FLVUtils.resetTimestamp(iFrame, (int) videoTimestamp);
enqueue(HttpChunk.make(iFrame));
}
videoHeaderSent = true;
}
if (data == null) return;
// 修改时间戳
// System.out.println("Time: " + videoTimestamp + ", current: " + timeoffset);
FLVUtils.resetTimestamp(data, (int) videoTimestamp);
videoTimestamp += (int)(timeoffset - lastVideoFrameTimeOffset);
lastVideoFrameTimeOffset = timeoffset;
enqueue(HttpChunk.make(data));
}
private FlvAudioTagEncoder audioEncoder = new FlvAudioTagEncoder();
MP3Encoder mp3Encoder = new MP3Encoder();
@Override
public void onAudioData(long timeoffset, byte[] data, FlvEncoder flvEncoder)
{
if (!videoHeaderSent) return;
byte[] mp3Data = mp3Encoder.encode(data);
if (mp3Data == null || mp3Data.length == 0) return;
AudioTag audioTag = new AudioTag(0, mp3Data.length + 1, AudioTag.MP3, (byte) 0, (byte)1, (byte) 0, mp3Data);
byte[] frameData = null;
try
{
ByteBuf audioBuf = audioEncoder.encode(audioTag);
frameData = ByteBufUtils.readReadableBytes(audioBuf);
}
catch (Exception e)
{
e.printStackTrace();
}
if (lastAudioFrameTimeOffset == 0) lastAudioFrameTimeOffset = timeoffset;
if (data == null) return;
FLVUtils.resetTimestamp(frameData, (int) audioTimestamp);
audioTimestamp += (int)(timeoffset - lastAudioFrameTimeOffset);
lastAudioFrameTimeOffset = timeoffset;
enqueue(HttpChunk.make(frameData));
}
@Override
public void close()
{
super.close();
mp3Encoder.close();
}
}