Потоковое видео с телефона на телефон с помощью сокета FD
Я новичок в программировании Android и обнаружил, что застрял. Я изучал различные способы потоковой передачи живого видео с телефона на телефон, и, кажется, он в основном функционален, за исключением, конечно, самой важной части: воспроизведения потока. Похоже, что отправка потока с одного телефона, но второй телефон не может воспроизвести поток.
Вот код для игровой стороны
public class VideoPlayback extends Activity implements Callback {
MediaPlayer mp;
private SurfaceView mPreview;
private SurfaceHolder holder;
private TextView mTextview;
public static final int SERVERPORT = 6775;
public static String SERVERIP="192.168.1.126";
Socket clientSocket;
private Handler handler = new Handler();
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mPreview = (SurfaceView) findViewById(R.id.surfaceView1);
mTextview = (TextView) findViewById(R.id.textView1);
holder = mPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mTextview.setText("Attempting to connect");
mp = new MediaPlayer();
Thread t = new Thread(){
public void run(){
try {
clientSocket = new Socket(SERVERIP,SERVERPORT);
handler.post(new Runnable() {
@Override
public void run() {
mTextview.setText("Connected to server");
}
});
handler.post(new Runnable() {
@Override
public void run() {
try {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(clientSocket);
pfd.getFileDescriptor().sync();
mp.setDataSource(pfd.getFileDescriptor());
pfd.close();
mp.setDisplay(holder);
mp.prepareAsync();
mp.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
А вот код для потоковой передачи
public class VideoStreaming extends Activity{
// User Interface Elements
VideoView mView;
TextView connectionStatus;
SurfaceHolder mHolder;
// Video variable
MediaRecorder recorder;
// Networking variables
public static String SERVERIP="";
public static final int SERVERPORT = 6775;
private Handler handler = new Handler();
private ServerSocket serverSocket;
/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Define UI elements
mView = (VideoView) findViewById(R.id.video_preview);
connectionStatus = (TextView) findViewById(R.id.connection_status_textview);
mHolder = mView.getHolder();
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
SERVERIP = "192.168.1.126";
// Run new thread to handle socket communications
Thread sendVideo = new Thread(new SendVideoThread());
sendVideo.start();
}
public class SendVideoThread implements Runnable{
public void run(){
// From Server.java
try {
if(SERVERIP!=null){
handler.post(new Runnable() {
@Override
public void run() {
connectionStatus.setText("Listening on IP: " + SERVERIP);
}
});
serverSocket = new ServerSocket(SERVERPORT);
while(true) {
//listen for incoming clients
Socket client = serverSocket.accept();
handler.post(new Runnable(){
@Override
public void run(){
connectionStatus.setText("Connected.");
}
});
try{
// Begin video communication
final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(client);
handler.post(new Runnable(){
@Override
public void run(){
recorder = new MediaRecorder();
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFile(pfd.getFileDescriptor());
recorder.setVideoFrameRate(20);
recorder.setVideoSize(176,144);
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
recorder.setPreviewDisplay(mHolder.getSurface());
try {
recorder.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
recorder.start();
}
});
} catch (Exception e) {
handler.post(new Runnable(){
@Override
public void run(){
connectionStatus.setText("Oops.Connection interrupted. Please reconnect your phones.");
}
});
e.printStackTrace();
}
}
} else {
handler.post(new Runnable() {
@Override
public void run(){
connectionStatus.setText("Couldn't detect internet connection.");
}
});
}
} catch (Exception e){
handler.post(new Runnable() {
@Override
public void run() {
connectionStatus.setText("Error");
}
});
e.printStackTrace();
}
// End from server.java
}
}
Я получаю следующую ошибку при попытке создать MediaPLayer
05-24 16:25:39.360: ERROR/MediaPlayerService(88): offset error
05-24 16:25:39.360: ERROR/MediaPlayer(11895): Unable to to create media player
05-24 16:25:39.360: WARN/System.err(11895): java.io.IOException: setDataSourceFD failed.: status=0x80000000
05-24 16:25:39.360: WARN/System.err(11895): at android.media.MediaPlayer.setDataSource(Native Method)
05-24 16:25:39.360: WARN/System.err(11895): at android.media.MediaPlayer.setDataSource(MediaPlayer.java:811)
05-24 16:25:39.360: WARN/System.err(11895): at com.conti.VideoPlayBack.VideoPlayback$1$2.run(VideoPlayback.java:63)
05-24 16:25:39.360: WARN/System.err(11895): at android.os.Handler.handleCallback(Handler.java:587)
05-24 16:25:39.360: WARN/System.err(11895): at android.os.Handler.dispatchMessage(Handler.java:92)
05-24 16:25:39.360: WARN/System.err(11895): at android.os.Looper.loop(Looper.java:132)
05-24 16:25:39.360: WARN/System.err(11895): at android.app.ActivityThread.main(ActivityThread.java:4025)
05-24 16:25:39.360: WARN/System.err(11895): at java.lang.reflect.Method.invokeNative(Native Method)
05-24 16:25:39.360: WARN/System.err(11895): at java.lang.reflect.Method.invoke(Method.java:491)
05-24 16:25:39.360: WARN/System.err(11895): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
05-24 16:25:39.360: WARN/System.err(11895): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
05-24 16:25:39.360: WARN/System.err(11895): at dalvik.system.NativeStart.main(Native Method)
У кого-нибудь есть решение для этого? Заранее спасибо!
4 ответа
Я нашел проект с открытым исходным кодом для реализации того, что я пытался. Он обрабатывает видео с метаданными через IP-камеру. Хотя он не отправляет видео непосредственно на телефон, он транслирует видео на различные устройства для просмотра. Исходный код можно найти на следующей странице проекта http://code.google.com/p/ipcamera-for-android/.
В Android 4.4 есть еще один способ воспроизведения живого потока MJPEG. Воспроизводимый поток должен транслироваться другим устройством через порт по UDP. Допустим, у нас есть поток, транслируемый в 192.168.0.101:8080. Мы можем воспроизвести поток, добавив WebView к нашему макету. Затем в нашей деятельности мы делаем следующее:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mjpeg_activity);
// Grab instance of WebView
WebView webView = (WebView)findViewById(R.id.webViewStream);
// Set page content for webview
webView.loadData("<html><head><meta name='viewport' content='target-densitydpi=device-dpi,initial-scale=1,minimum-scale=1,user-scalable=yes'/></head><body><center><img src=\"http://192.168.0.101:8080/\" alt=\"Stream\" align=\"middle\"></center></body></html>", "text/html", null);
webView.getSettings().setBuiltInZoomControls(true);
}
В контенте мы говорим веб-странице использовать dpi устройства. Чтобы помочь пользователю увеличить масштаб на веб-странице, я добавил следующую начальную шкалу =1, минимальная шкала =1, масштабируемая пользователем = да. Изначально изображение имеет оригинальный размер и не может быть меньше. Теперь пользователь может масштабировать, чтобы увеличить изображение и уменьшить его до исходного размера. Удаление минимального масштаба обеспечит пользователю полный контроль над масштабированием, но может привести к тому, что изображение станет настолько маленьким, что вы не сможете его найти.
Вы должны установить выходной формат рекордера 8(MPEG-2TS, доступно только для Android версии 3.0+). В этом случае запишите видео в этом формате и отправьте поток на другой телефон и сохраните его в файл. И воспроизведите его после записи некоторых данных в файл, после чего вы сможете увидеть прямую трансляцию.
Примечание. Вы не можете напрямую воспроизводить дескриптор файла сокета, потому что сокет fd не доступен для поиска. Если вы используете сокет fd, вы получите "ошибку смещения". Запись возможна, но игра ограничена.
Загрузите исходный код с: http://code.google.com/p/ipcamera-for-android/( https://github.com/Teaonly/android-eye)
Сначала соберите jni (используйте ndk-build с cygwin)
Я мог бы успешно построить этот проект
Взгляните на потоковую передачу на Android MediaPlayer, в которой могут быть полезные советы о том, как выполнять потоковую передачу. Я подозреваю, что проблема в том, что Android пытается найти файл, но, будучи сетевым сокетом, не может. Может быть, какой-то буфер диска / памяти, который поддерживает поиск, может помочь?