質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.23%

socket通信での画像転送(android)

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 188

Mustard

score 5

Wi-Fi Directを使いP2P通信で画像を転送するandroidアプリを作ろうとしています(android 7.0)。
WiFiDirectServiceDiscoveryを参考に接続の構築は実装できたのですが、接続完了後にソケットを通じて画像を送ると受信側には真っ黒の画像が表示されてしまいます。
現在はbitmapをbyte配列に変換した上でstreamに流し込み、受信側で再度bitmapに変換していますがreadやwriteの手順がおかしいのか正常な画像が転送できません。
以下に実装したコードを示します。問題点のご指摘および実装案の提示にご助力お願いいたします。

public class WiFiChatFragment extends Fragment {
--(略)--
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
       --(略)--
       //ボタンのタッチでカメラから画像を取得・送信
        view.findViewById(R.id.button1).setOnClickListener(
                new View.OnClickListener() {

                    @Override
                    public void onClick(View arg0) {
                        Bitmap bmp = null;
                        try {
                            mCaptureSession.stopRepeating(); // プレビューの更新を止める
                            if(mTextureView.isAvailable()) {
                               bmp= mTextureView.getBitmap();//bitmapを取得
                                if(bmp != null && imgManager != null){
                                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                    bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);//bitmap -> byte(jpeg)
                                    byte[] jpgarr = baos.toByteArray();
                                    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
                                    chatManager.write(jpgarr);//Streamへ流す

                                }
                            }
                            mTextureView.findViewById(R.id.myTextureView).setVisibility(View.GONE);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }
                });
        return view;
    }
}
public class ChatManager implements Runnable{
    private Socket socket = null;
    private Handler handler;
    public ChatManager(Socket socket, Handler handler) {
        this.socket = socket;
        this.handler = handler;
    }
    private InputStream iStream;
    private OutputStream oStream;
    private static final String TAG = "ChatHandler";
    @Override
    public void run() {
        try {
            iStream = socket.getInputStream();
            oStream = socket.getOutputStream();
            byte[] buffer = new byte[1024];
            int bytes;
            while (true) {
                try {
                    // Read from the InputStream
                    bytes = iStream.read(buffer);
                    if (bytes == -1) {
                        break;
                    }
                    // Send the obtained bytes to the UI Activity
                    handler.obtainMessage(WiFiServiceDiscoveryActivity.MESSAGE_READ,bytes, -1, buffer).sendToTarget();
                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void write(byte[] buffer) {
        try {
            oStream.write(buffer);
        } catch (IOException e) {
            Log.e(TAG, "Exception during write", e);
        }
    }
}
//取得した画像を表示
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MESSAGE_READ:
                byte[] readBuf = (byte[]) msg.obj;
                Bitmap readImg = null;
                readImg = BitmapFactory.decodeByteArray(readBuf, 0, readBuf.length);//byte -> bitmap

                 (sendFragment).pushMessage(readImg);//List<Bitmap>へデータをプッシュ

                break;

            case MY_HANDLE:
              --(略)--
        }
        return true;
    }

試したこととして、sendFragment内でbitmapをbyte配列に変換後にstreamに流す代わりにその場でbyteからbitmapに戻し描画させたところ、正常な画像が表示されました。このことから通信以外の理由で画像データが壊れた可能性は低いと考えています。

                      try {
                            mCaptureSession.stopRepeating(); // プレビューの更新を止める
                            if(mTextureView.isAvailable()) {
                               bmp= mTextureView.getBitmap();//bitmapを取得
                                if(bmp != null && imgManager != null){
                                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                    bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);//bitmap -> byte(jpeg)
                                    byte[] jpgarr = baos.toByteArray();
                                    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
                                    //chatManager.write(jpgarr);
                                    //再度byteからBitmapへ(この場合正しい画像が描画された)
                                    Bitmap readImg = null;
                                    readImg = BitmapFactory.decodeByteArray(jpgarr, 0, jpgarr.length);//byte -> bitmap
                                    pushMessage(readImg);//List<Bitmap>へデータをプッシュ
                                }
                            }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • jimbe

    2019/05/05 03:16

    受信側で, 送信したデータが全て受信されているか確認はされましたでしょうか?

    キャンセル

  • Mustard

    2019/05/05 12:42

    jimbeさん、質問ありがとうございます。
    送信側の変数jpgarrおよび受信側の変数readImgを確認したところ
    jpgarr={byte[1158931]@4672}
    0=-1
    1=-40
    2=-1
    3=-32
    4=0
    5=16
    --(略)--

    readImg={byte[1024]@4710}
    0=25
    1=-68
    2=-23
    3=-98
    4=65
    5=70
    --(略)--
    となっており、配列の大きさが全く異なっていました。
    受信した黒画像も一枚ではなく複数枚受信していることもわかりましたので、buffer単位で分割されていまっていると考えています。
    これらを一つの画像として受信する方法などご存知でしょうか。

    キャンセル

回答 1

check解決した方法

0

obtainMessageの位置を画像データを全て受信した後に呼び出すことで解決いたしました。
下記のように変更したところ正しい画像が転送されました。
方針を決定づける質問をして頂いたjimbeさん本当にありがとうございました。

--(略)--
public void run() {

        try {

            iStream = socket.getInputStream();
            oStream = socket.getOutputStream();
            byte[] buffer = new byte[1024];
            int bytes;

            ByteArrayOutputStream bospv = new ByteArrayOutputStream();
            copyFile(iStream,bospv);
            pvbyte=bospv.toByteArray();
            handler.obtainMessage(WiFiServiceDiscoveryActivity.MESSAGE_READ,pvbyte).sendToTarget();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
--(略)--
public static boolean copyFile(InputStream inputStream, OutputStream out) {
        byte buf[] = new byte[1024];
        int len;
        try {
            while ((len = inputStream.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
            out.close();
            inputStream.close();
        } catch (IOException e) {
            return false;
        }
        return true;
    }

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる