Java 在Android上解码/播放视频流并录制文件的最佳实践
我正在编写一个应用程序,通过TCP连接收集h264流,并尽可能快地将其显示在Java 在Android上解码/播放视频流并录制文件的最佳实践,java,android,h.264,Java,Android,H.264,我正在编写一个应用程序,通过TCP连接收集h264流,并尽可能快地将其显示在TextureView上(可能越快越好)。 它工作得很好,但我打赌它可以做得更好。现在,我需要添加一个录音功能,我正在猜测如何在不损失表演的情况下做到这一点。 这是我的代码: public void run() { byte[] nal = new byte[NAL_SIZE_INC]; int nalLen = 0; int numZeroes = 0;
TextureView上(可能越快越好)。
它工作得很好,但我打赌它可以做得更好。现在,我需要添加一个录音功能,我正在猜测如何在不损失表演的情况下做到这一点。
这是我的代码:
public void run() {
byte[] nal = new byte[NAL_SIZE_INC];
int nalLen = 0;
int numZeroes = 0;
int numReadErrors = 0;
int connection_retries = 0;
try {
decoder = MediaCodec.createDecoderByType("video/avc");
byte[] buffer = new byte[BUFFER_SIZE];
do {
if(camera.getStreamingProtocol() == Protocol.UDP)
reader = new UdpListner(camera.getPort());
else //if(camera.getStreamingProtocol() == Protocol.TCP)
reader = new TcpIpReader(camera.getAddress(), camera.getPort());
connection_retries++;
Thread.sleep(VIDEO_STREAM_RESPAWN);
} while (!reader.isConnected() && (connection_retries < MAX_CONN_RETRIES));
if (!reader.isConnected()) {
//throw new Exception();
Log.d(getClass().getName(), "Link respawn: " + connection_retries);
return;
}
while (keep_running) {
int len = reader.read(buffer);
if (!keep_running) break;
if (len > 0) {
numReadErrors = 0;
for (int i = 0; i < len && keep_running; i++) {
if (nalLen == nal.length) {
nal = Arrays.copyOf(nal, nal.length + NAL_SIZE_INC);
}
nal[nalLen++] = buffer[i];
if (buffer[i] == 0) {
numZeroes++;
} else {
if (buffer[i] == 1 && numZeroes == 3) {
if (nalLen > 4) {
int nalType = processNal(nal, nalLen - 4);
if (!keep_running) break;
if (nalType == -1) {
nal[0] = nal[1] = nal[2] = 0;
nal[3] = 1;
}
}
nalLen = 4;
}
numZeroes = 0;
}
}
} else {
numReadErrors++;
if (numReadErrors >= MAX_READ_ERRORS) {
setVideoMessage(R.string.error_lost_connection);
break;
}
}
if (format != null && decoding) {
if (!keep_running) break;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int index;
do {
index = decoder.dequeueOutputBuffer(info, 0);
if (!keep_running) break;
if (index >= 0) {
decoder.releaseOutputBuffer(index, true);
}
} while (index >= 0);
}
}
} catch (Exception ex) {
Log.e(getClass().getName(), "Exception: " + ex.toString());
if (reader == null || !reader.isConnected()) {
setVideoMessage(R.string.error_couldnt_connect);
finishHandler.postDelayed(finishRunner, FINISH_TIMEOUT);
} else {
setVideoMessage(R.string.error_lost_connection);
}
ex.printStackTrace();
}
if (reader != null) {
try {
reader.close();
} catch (Exception ex) {
Log.i(getClass().getName(), "Exception: " + ex.getMessage());
}
reader = null;
}
if (decoder != null) {
try {
setDecodingState(false);
decoder.release();
} catch (Exception ex) {
Log.e(getClass().getName(), "Exception: " + ex.getMessage());
}
decoder = null;
}
}
public void run(){
byte[]nal=新字节[nal_SIZE_INC];
int-nalLen=0;
int numZeroes=0;
int numReadErrors=0;
int连接重试次数=0;
试一试{
解码器=MediaCodec.createDecoderByType(“视频/avc”);
字节[]缓冲区=新字节[缓冲区大小];
做{
if(camera.getStreamingProtocol()==Protocol.UDP)
reader=newudplistner(camera.getPort());
else//if(camera.getStreamingProtocol()==Protocol.TCP)
reader=新的tcpipreder(camera.getAddress(),camera.getPort());
连接重试++;
线程。睡眠(视频、流、重生);
}而(!reader.isConnected()&&(连接重试次数<最大连接重试次数));
如果(!reader.isConnected()){
//抛出新异常();
Log.d(getClass().getName(),“链接重新启动:”+连接重试);
返回;
}
while(保持运行){
int len=reader.read(缓冲区);
如果(!保持运行)中断;
如果(len>0){
numReadErrors=0;
对于(int i=0;i4){
int-nalType=processNal(nal,nalLen-4);
如果(!保持运行)中断;
如果(nalType==-1){
nal[0]=nal[1]=nal[2]=0;
nal[3]=1;
}
}
纳伦=4;
}
numZeroes=0;
}
}
}否则{
numReadErrors++;
如果(numReadErrors>=最大读取错误){
setVideoMessage(R.string.error\u失去连接);
打破
}
}
if(格式!=null&解码){
如果(!保持运行)中断;
MediaCodec.BufferInfo=新的MediaCodec.BufferInfo();
整数指数;
做{
index=decoder.dequeueOutputBuffer(info,0);
如果(!保持运行)中断;
如果(索引>=0){
解码器.releaseOutputBuffer(索引,true);
}
}而(指数>=0);
}
}
}捕获(例外情况除外){
Log.e(getClass().getName(),“异常:+ex.toString());
if(reader==null | |!reader.isConnected()){
setVideoMessage(R.string.error\u couldn\u connect);
postDelayed(finishRunner,完成超时);
}否则{
setVideoMessage(R.string.error\u失去连接);
}
例如printStackTrace();
}
if(读卡器!=null){
试一试{
reader.close();
}捕获(例外情况除外){
Log.i(getClass().getName(),“异常:+ex.getMessage());
}
reader=null;
}
if(解码器!=null){
试一试{
setDecodingState(假);
decoder.release();
}捕获(例外情况除外){
Log.e(getClass().getName(),“异常:+ex.getMessage());
}
解码器=空;
}
}
当然,这是run()
方法的线程
派生对象,它管理显示视频的片段上的作业
创建一个简单的缓冲输出流并在其上写入从传入流收集的每个缓冲区
,应该可以正常工作,否则可能会延迟视频渲染
我必须将头数据添加到h264输出文件以使其可读
有没有办法优化接收/显示部分?我愿意接受任何建议。。。我想用UDP来代替TCP,只是想提一下
致以最良好的祝愿,
迈克