接收端解码、自定义view绘制帧
H264 解码
public class Receive {
static {
System . loadLibrary ( "H264Decoder_neon" ) ;
}
public native long CreateH264Packer ( ) ;
public native int PackH264Frame ( long handle, byte [ ] pPayload, int payloadlen, int bMark, int pts, int sequence, byte [ ] frmbuf) ;
public native void DestroyH264Packer ( long handle) ;
public native int CreateDecoder ( int width, int height) ;
public native int DecoderNal ( byte [ ] in, int insize, byte [ ] out) ;
public native int DestoryDecoder ( ) ;
}
自定义播放view
import android. content. Context ;
import android. graphics. Bitmap ;
import android. graphics. Bitmap. Config ;
import android. graphics. Canvas ;
import android. graphics. Matrix ;
import android. graphics. Paint ;
import android. graphics. Rect ;
import android. graphics. RectF ;
import android. media. MediaRecorder ;
import android. util. AttributeSet ;
import android. util. DisplayMetrics ;
import android. view. SurfaceView ;
import android. view. View ;
import java. io. IOException ;
import java. nio. ByteBuffer ;
public class VideoPlayView extends View {
public int width = 800 ;
public int height = 600 ;
public byte [ ] mPixel = new byte [ width * height * 2 ] ;
public ByteBuffer buffer = ByteBuffer . wrap ( mPixel) ;
public Bitmap VideoBit = Bitmap . createBitmap ( width, height, Config . RGB_565) ;
private Matrix matrix = null ;
public Bitmap VideoBit2 ;
private RectF rectF;
public VideoPlayView ( Context context, AttributeSet attrs) {
super ( context, attrs) ;
matrix = new Matrix ( ) ;
DisplayMetrics dm = getResources ( ) . getDisplayMetrics ( ) ;
int W = dm. widthPixels;
int H = dm. heightPixels;
rectF = new RectF ( 0 , 0 , W , H ) ;
}
@Override
protected void onDraw ( Canvas canvas) {
super . onDraw ( canvas) ;
buffer. rewind ( ) ;
try {
VideoBit . copyPixelsFromBuffer ( buffer) ;
setAngle ( ) ;
Bitmap bitmap = convert ( VideoBit2 ) ;
canvas. drawBitmap ( bitmap, null , rectF, null ) ;
} catch ( Exception e) {
}
}
private void setAngle ( ) {
matrix. reset ( ) ;
matrix. setRotate ( 270 ) ;
VideoBit2 = Bitmap . createBitmap ( VideoBit , 0 , 0 ,
VideoBit . getWidth ( ) , VideoBit . getHeight ( ) , matrix, true ) ;
}
Bitmap convert ( Bitmap a)
{
int w = a. getWidth ( ) ;
int h = a. getHeight ( ) ;
Bitmap newb = Bitmap . createBitmap ( a. getWidth ( ) , a. getHeight ( ) , Config . ARGB_8888) ;
Canvas cv = new Canvas ( newb) ;
Matrix m = new Matrix ( ) ;
Bitmap new2 = Bitmap . createBitmap ( a, 0 , 0 , w, h, m, true ) ;
cv. drawBitmap ( new2, new Rect ( 0 , 0 , new2. getWidth ( ) , new2. getHeight ( ) ) , new Rect ( 0 , 0 , a. getWidth ( ) , a. getHeight ( ) ) , null ) ;
return newb;
}
private Bitmap adjustPhotoRotation ( Bitmap bm, final int orientationDegree) {
Matrix m = new Matrix ( ) ;
m. setRotate ( orientationDegree, ( float ) bm. getWidth ( ) / 2 , ( float ) bm. getHeight ( ) / 2 ) ;
float targetX, targetY;
if ( orientationDegree == 90 ) {
targetX = bm. getHeight ( ) ;
targetY = 0 ;
} else {
targetX = bm. getHeight ( ) ;
targetY = bm. getWidth ( ) ;
}
final float [ ] values = new float [ 9 ] ;
m. getValues ( values) ;
float x1 = values[ Matrix . MTRANS_X] ;
float y1 = values[ Matrix . MTRANS_Y] ;
m. postTranslate ( targetX - x1, targetY - y1) ;
Bitmap bm1 = Bitmap . createBitmap ( bm. getHeight ( ) , bm. getWidth ( ) , Config . ARGB_8888) ;
Paint paint = new Paint ( ) ;
Canvas canvas = new Canvas ( bm1) ;
canvas. drawBitmap ( bm, m, paint) ;
return bm1;
}
}
使用
private VideoPlayView view = null ;
private Receive receive;
private boolean isRunning;
private RtpSocket rtp_socket = null ;
private RtpPacket rtp_receive_packet = null ;
private long decoder_handle = 0 ;
private byte [ ] frmbuf = new byte [ 65536 ] ;
private byte [ ] socket_receive_Buffer = new byte [ 65536 ] ;
private byte [ ] buffer = new byte [ 65536 ] ;
private String remote_ip;
private int remote_port;
private LinearLayout linear_open, linear_refuse, linear_photo, linear_video;
public void doStart ( ) {
receive= new Receive ( ) ;
if ( rtp_socket == null ) {
try {
rtp_socket = new RtpSocket ( new SipdroidSocket ( 19888 ) , InetAddress . getByName ( remote_ip) , remote_port) ;
} catch ( SocketException e) {
e. printStackTrace ( ) ;
} catch ( UnknownHostException e) {
e. printStackTrace ( ) ;
}
rtp_receive_packet = new RtpPacket ( socket_receive_Buffer, 0 ) ;
decoder_handle = receive. CreateH264Packer( ) ;
receive. CreateDecoder( Constants . WIDTH, Constants . HEIGHT) ;
isRunning = true ;
DecoderThread decoder = new DecoderThread ( ) ;
decoder. start ( ) ;
}
}
class DecoderThread extends Thread {
@Override
public void run ( ) {
while ( isRunning) {
try {
rtp_socket. receive ( rtp_receive_packet) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
int packetSize = rtp_receive_packet. getPayloadLength ( ) ;
if ( packetSize <= 0 ) {
continue ;
}
if ( rtp_receive_packet. getPayloadType ( ) != 2 )
{
continue ;
}
System . arraycopy ( socket_receive_Buffer, 12 , buffer, 0 , packetSize) ;
int sequence = rtp_receive_packet. getSequenceNumber ( ) ;
long timestamp = rtp_receive_packet. getTimestamp ( ) ;
int bMark = rtp_receive_packet. hasMarker ( ) == true ? 1 : 0 ;
int frmSize = receive. PackH264Frame( decoder_handle, buffer, packetSize, bMark, ( int ) timestamp, sequence, frmbuf) ;
if ( frmSize <= 0 ) {
continue ;
}
receive. DecoderNal( frmbuf, frmSize, view. mPixel) ;
view. postInvalidate ( ) ;
}
if ( decoder_handle != 0 ) {
receive. DestroyH264Packer( decoder_handle) ;
decoder_handle = 0 ;
}
if ( rtp_socket != null ) {
rtp_socket. close ( ) ;
rtp_socket = null ;
}
receive. DestoryDecoder( ) ;
}
}
```[ 源码链接] ( https: / / gitee. com/ zxy0822/ send)