Skip to content

Commit

Permalink
video stream working...
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasb committed Apr 5, 2012
1 parent cf15670 commit 6817668
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 16 deletions.
4 changes: 3 additions & 1 deletion .gitignore
@@ -1,5 +1,7 @@
local.properties
.idea/
bin/
gen/
libs/
obj/
out/
local.properties
3 changes: 2 additions & 1 deletion AndroidManifest.xml
Expand Up @@ -3,6 +3,7 @@
package="se.forskningsavd"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar">
<activity android:name="MainActivity"
Expand All @@ -14,4 +15,4 @@
</intent-filter>
</activity>
</application>
</manifest>
</manifest>
6 changes: 5 additions & 1 deletion AutomatonBrain.iml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="ANDROID_MODULE" version="4">
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android" name="Android">
<configuration>
Expand All @@ -20,6 +20,10 @@
<option name="RUN_PROCESS_RESOURCES_MAVEN_TASK" value="true" />
<option name="GENERATE_UNSIGNED_APK" value="false" />
<option name="CUSTOM_DEBUG_KEYSTORE_PATH" value="" />
<option name="PACK_TEST_CODE" value="false" />
<option name="RUN_PROGUARD" value="false" />
<option name="PROGUARD_CFG_PATH" value="/proguard.cfg" />
<resOverlayFolders />
</configuration>
</facet>
</component>
Expand Down
19 changes: 19 additions & 0 deletions jni/Android.mk
@@ -0,0 +1,19 @@
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := decoder-jni
LOCAL_CPPFLAGS := -D__STDC_CONSTANT_MACROS
LOCAL_C_INCLUDES := ffmpeg-android/build/ffmpeg/${TARGET_ARCH_ABI}/include
LOCAL_SRC_FILES := decoder-jni.c
LOCAL_STATIC_LIBRARIES += \
avcodec \
avcore \
avutil \
swscale \
#
LOCAL_LDLIBS += \
-ljnigraphics \
#
include $(BUILD_SHARED_LIBRARY)

include ffmpeg-android/Android.mk
71 changes: 71 additions & 0 deletions jni/decoder-jni.c
@@ -0,0 +1,71 @@
#include <jni.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <stdbool.h>
#include <android/bitmap.h>

AVCodecContext *pCodecCtx; // FFMPEG codec context
AVCodec *pCodec; // Pointer to FFMPEG codec (H264)
AVFrame *pFrame; // Used in the decoding process
struct SwsContext *convertCtx; // Used in the scaling/conversion process
AVPacket avpkt; // Used in the decoding process
int temp; // Various uses


bool Java_se_forskningsavd_Decoder_init(JNIEnv* env, jobject thiz) {
avcodec_init();
avcodec_register_all();
pCodecCtx = avcodec_alloc_context();
pCodec = avcodec_find_decoder( CODEC_ID_H264 );
av_init_packet( &avpkt );
if( !pCodec ) {
return false;
//printf( "RoboCortex [error]: Unable to initialize decoder\n" );
//exit( EXIT_DECODER );
}
avcodec_open( pCodecCtx, pCodec );

// Allocate decoder frame
pFrame = avcodec_alloc_frame();
return true;
}

bool Java_se_forskningsavd_Decoder_decode(JNIEnv *env, jobject thiz, jbyteArray frame, jobject bitmap) {
AndroidBitmapInfo bitmapInfo;
if (AndroidBitmap_getInfo(env, bitmap, &bitmapInfo) != 0) {
return false;
}

uint8_t *dest_data = 0; //TODO
avpkt.data = (*env)->GetByteArrayElements(env, frame, 0);
avpkt.size = (*env)->GetArrayLength(env, frame);
avpkt.flags = AV_PKT_FLAG_KEY;
int len = avcodec_decode_video2( pCodecCtx, pFrame, &temp, &avpkt );
(*env)->ReleaseByteArrayElements(env, frame, avpkt.data, JNI_ABORT);

if (len < 0 ) {
return false;
//printf( "RoboCortex [info]: Decoding error (packet loss)\n" );
} else {
void *bitmapData;
AndroidBitmap_lockPixels(env, bitmap, &bitmapData);
const uint8_t * data[1] = { bitmapData };
int linesize[1] = { bitmapInfo.stride };

// Create scaling & color-space conversion context
convertCtx = sws_getContext( pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
bitmapInfo.width, bitmapInfo.height, PIX_FMT_BGRA, SWS_AREA, NULL, NULL, NULL);

// Scale and convert the frame
sws_scale( convertCtx, (const uint8_t**) pFrame->data, pFrame->linesize, 0,
pCodecCtx->height, (uint8_t * const*) data, linesize );

// Cleanup
sws_freeContext( convertCtx );

//
AndroidBitmap_unlockPixels(env, bitmap);
}
return true;
}

53 changes: 44 additions & 9 deletions src/se/forskningsavd/Communicator.java
@@ -1,5 +1,8 @@
package se.forskningsavd;

import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.io.IOException;
Expand All @@ -11,33 +14,52 @@
import java.util.ArrayList;

class Communicator {
public interface Callback {
public void onTargetImageChanged(Bitmap bitmap);
}

static class ReceiverThread extends Thread {
private final DatagramSocket mSocket;
private boolean mRunning = true;
private final SenderThread mSenderThread;
private final Decoder mDecoder;
private final Bitmap mTargetBitmap;
private final Handler mHandler;

public ReceiverThread(DatagramSocket socket, SenderThread senderThread) {
public ReceiverThread(DatagramSocket socket, SenderThread senderThread, Decoder decoder, Bitmap targetBitmap, Handler handler) {
mSocket = socket;
mSenderThread = senderThread;
mDecoder = decoder;
mTargetBitmap = targetBitmap;
mHandler = handler;
}

@Override
public void run() {
byte[] buf = new byte[1000];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
byte[] buf = new byte[3000];
while (mRunning) {
try {
DatagramPacket dp = new DatagramPacket(buf, buf.length);
mSocket.receive(dp);
StringBuilder debug = new StringBuilder();
for (int i = 0; i < dp.getLength(); i++) {
debug.append(String.format("%02x", dp.getData()[i]));
final int length = dp.getLength();
if (length < 1000) {
for (int i = 0; i < length; i++) {
debug.append(String.format("%02x", dp.getData()[i]));
}
}
String rcvd = "rcvd from " + dp.getAddress() + ", " + dp.getPort() + ": "
String rcvd = "rcvd from " + dp.getAddress() + ", " + dp.getPort() + ", " + length + " bytes : "
+ debug;
Log.d("XXX", rcvd);

ByteBuffer data = ByteBuffer.wrap(dp.getData());
if (data.get(0) == 'D' &&
if (data.get(0) == 0 &&
data.get(1) == 0 &&
data.get(2) == 0 &&
data.get(3) == 1) {
Log.d("decode", "h264 frame decode= " + mDecoder.decode(data.array(), mTargetBitmap));
mHandler.sendEmptyMessage(0);
} else if (data.get(0) == 'D' &&
data.get(1) == 'A' &&
data.get(2) == 'T' &&
data.get(3) == 'A') {
Expand Down Expand Up @@ -188,9 +210,13 @@ public void addTrustedMessage(byte[] ident, byte[] message) {
private ReceiverThread mReceiverThread;
private SenderThread mSenderThread;
private final Navigator mNavigator;
private final Bitmap mTargetBitmap;
private final Callback mCallback;

public Communicator(Navigator nav) {
public Communicator(Navigator nav, Bitmap target, Callback callback) {
mNavigator = nav;
mTargetBitmap = target;
mCallback = callback;
}

public void connect() {
Expand All @@ -206,7 +232,16 @@ public void connect() {
mSenderThread = new SenderThread(socket, mNavigator);
mSenderThread.start();

mReceiverThread = new ReceiverThread(socket, mSenderThread);
Decoder d = new Decoder();
Log.d("decode", "init(): " + d.init());

final Handler handler = new Handler(new Handler.Callback() {
public boolean handleMessage(Message message) {
mCallback.onTargetImageChanged(mTargetBitmap);
return false;
}
});
mReceiverThread = new ReceiverThread(socket, mSenderThread, d, mTargetBitmap, handler);
mReceiverThread.start();
}

Expand Down
12 changes: 12 additions & 0 deletions src/se/forskningsavd/Decoder.java
@@ -0,0 +1,12 @@
package se.forskningsavd;

import android.graphics.Bitmap;

public class Decoder {
public native boolean init();
public native boolean decode(byte[] frame, Bitmap target);

static {
System.loadLibrary("decoder-jni");
}
}
22 changes: 18 additions & 4 deletions src/se/forskningsavd/MainActivity.java
@@ -1,11 +1,13 @@
package se.forskningsavd;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;

Expand All @@ -15,9 +17,15 @@ public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ImageView video = new ImageView(this);

Navigator nav = new Navigator();
mCommunicator = new Communicator(nav);
Bitmap target = Bitmap.createBitmap(320, 240, Bitmap.Config.ARGB_8888);
mCommunicator = new Communicator(nav, target, new Communicator.Callback() {
public void onTargetImageChanged(Bitmap bitmap) {
video.invalidate();
}
});

LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
Expand All @@ -41,9 +49,15 @@ public void onClick(View view) {
});
layout.addView(helloWorld);

FrameLayout frame = new FrameLayout(this);

video.setImageBitmap(target);
frame.addView(video);

NavigationView navigationView = new NavigationView(this, nav);
LayoutParams p = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
layout.addView(navigationView, p);
frame.addView(navigationView);

layout.addView(frame, MATCH_PARENT, MATCH_PARENT);

setContentView(layout);
}
Expand Down

0 comments on commit 6817668

Please sign in to comment.