AndroidスクリーンレコーダーからキャプチャしたビデオはWebブラウザで再生できません

miclendor

コンポーネントのWebブラウザーでビデオを再生しようとすると、ファイルがまったく再生されないという問題が発生します。ファイルは、MediaRecorderとMediaProjectionを使用してAndroidデバイスでキャプチャされ、画面を記録しようとしました。MediaRecorderを初期化する方法のコードは次のとおりです。

public class ScreenRecordService extends Service {

private static final String TAG = ScreenRecordService.class.getSimpleName();

private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final int DISPLAY_WIDTH = 960;
private static final int DISPLAY_HEIGHT = 540;

private float mDensity;
private int mRotation;
private boolean mIsRecording;

private MediaProjectionManager mProjectionManager;
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private MediaProjectionCallback mMediaProjectionCallback;
private MediaRecorder mMediaRecorder;
private String mFilePath;

static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}

private class MediaProjectionCallback extends MediaProjection.Callback {
    @Override
    public void onStop() {
        try {
            if (mIsRecording) {
                mIsRecording = false;
                mMediaRecorder.stop();
                mMediaRecorder.reset();
            }
            mMediaProjection = null;
            stopScreenSharing();

            HermesEventBus.getDefault().post(new EventRecorder.Server(EventRecorder.SERVER_STOP_SUCCESS));
        } catch (Exception e) {
            e.printStackTrace();
            HermesEventBus.getDefault().post(new EventRecorder.Server(EventRecorder.SERVER_STOP_FAIL));
        }
    }
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onStopCall(EventRecorder.Client clientEvent) {
    if (clientEvent.messageType == EventRecorder.CLIENT_STOP_RECORD) {
        stopRecording();
    }
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    super.onCreate();
    HermesEventBus.getDefault().register(this);
    AppManager.getInstance().addService(this);
    mProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
    mMediaProjectionCallback = new MediaProjectionCallback();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (mProjectionManager == null) {
        mProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
    }
    if (intent != null) {
        mDensity = intent.getFloatExtra("density", 0f);
        mRotation = intent.getIntExtra("rotation", 0);
        mFilePath = intent.getStringExtra(Const.Intent.INFO);
        JLog.d(TAG, mFilePath);

        startRecording(intent);
    }
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    AppManager.getInstance().removeService(this);
}

private void startRecording(Intent intent) {
    try {
        if (!mIsRecording) {
            mMediaProjection = mProjectionManager.getMediaProjection(RESULT_OK, intent);
            mMediaProjection.registerCallback(mMediaProjectionCallback, null);
            initRecorder();
            mVirtualDisplay = createVirtualDisplay();
            mMediaRecorder.start();
            mIsRecording = true;

            HermesEventBus.getDefault().post(new EventRecorder.Server(EventRecorder.SERVER_START_SUCCESS));
        }
    } catch (Exception e) {
        e.printStackTrace();
        mIsRecording = false;
        HermesEventBus.getDefault().post(new EventRecorder.Server(EventRecorder.SERVER_START_FAIL));
    }
}

private void stopRecording() {
    try {
        if (mIsRecording) {
            mMediaRecorder.stop();
            mMediaRecorder.reset();
            stopScreenSharing();

            HermesEventBus.getDefault().post(new EventRecorder.Server(EventRecorder.SERVER_STOP_SUCCESS));
        }
    } catch (Exception e) {
        e.printStackTrace();
        mIsRecording = false;
        if (mMediaRecorder != null) {
            mMediaRecorder.reset();
        }
        stopScreenSharing();
        HermesEventBus.getDefault().post(new EventRecorder.Server(EventRecorder.SERVER_STOP_FAIL));
    }
}

private VirtualDisplay createVirtualDisplay() {
    return mMediaProjection.createVirtualDisplay(getString(R.string.video_record), DISPLAY_WIDTH, DISPLAY_HEIGHT, (int) mDensity,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);
}

private void stopScreenSharing() {
    if (mVirtualDisplay == null) {
        return;
    }
    mVirtualDisplay.release();
    destroyMediaProjection();
    mIsRecording = false;
}

private void initRecorder() {
    int bitRateQuality = PrefsUtils.getInstance(this, Const.Pref.FILE_COMMON).getInt(Const.Pref.KEY_RECORD_BITRATE, Const.Setting.QUALITY_MID);
    int bitRate;
    if (bitRateQuality == Const.Setting.QUALITY_HIGH) {
        bitRate = 1536000;
    } else if (bitRateQuality == Const.Setting.QUALITY_MID) {
        bitRate = 1024 * 1024;
    } else {
        bitRate = 512000;
    }
    if (mMediaRecorder == null) {
        mMediaRecorder = new MediaRecorder();
    }
    try {
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); //THREE_GPP
        mMediaRecorder.setOutputFile(mFilePath);
        mMediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setVideoFrameRate(8); // 30
        mMediaRecorder.setVideoEncodingBitRate(bitRate);
        int orientation = ORIENTATIONS.get(mRotation + 90);
        mMediaRecorder.setOrientationHint(orientation);
        mMediaRecorder.prepare();
        mMediaRecorder.setOnInfoListener((mr, what, extra) -> {
            if (what == MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
                stopRecording();
            }
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void destroyMediaProjection() {
    if (mMediaProjection != null) {
        mMediaProjection.unregisterCallback(mMediaProjectionCallback);
        mMediaProjection.stop();
        mMediaProjection = null;
    }
    JLog.i(TAG, "MediaProjection Stopped");
}

}

そして、これが私がアップロードしたファイルです。

http://eachdoctorvideotest.oss-cn-shenzhen.aliyuncs.com/1103/videoRecord/input/ali_TVM1103vRecordIn20190212154904841.mp4

URLを任意のブラウザに貼り付けるだけで(私はChromeを使用しており、Chromeは再生できませんが、Safariは再生できます)、ファイルを再生できないことがわかります。ただし、PC上のサードパーティのメディアプレーヤーで再生できます。それで、ファイルがブラウザで再生できないという正確な問題は何ですか?

このビデオファイルは、もともと2つのファイル(ビデオトラックとオーディオトラック)で生成されました。mp4parserを使用してトラックを結合すると、次のライブラリが表示される場合があります。

https://github.com/sannies/mp4parser

これらを組み合わせるために使用したキーコードは次のとおりです。

    public boolean muxAacMp4(String mp4Path, String aacPath, String outPath) {
    boolean flag = false;
    try {
        AACTrackImpl aacTrack = new AACTrackImpl(new FileDataSourceImpl(aacPath));
        Movie videoMovie = MovieCreator.build(mp4Path);
        Track videoTracks = null;
        for (Track videoMovieTrack : videoMovie.getTracks()) {
            if ("vide".equals(videoMovieTrack.getHandler())) {
                videoTracks = videoMovieTrack;
            }
        }

        Movie resultMovie = new Movie();
        resultMovie.addTrack(videoTracks);
        resultMovie.addTrack(aacTrack);

        Container out = new DefaultMp4Builder().build(resultMovie);
        FileOutputStream fos = new FileOutputStream(new File(outPath));
        out.writeContainer(fos.getChannel());
        fos.close();
        flag = true;
        Log.e("update_tag", "merge finish");
    } catch (Exception e) {
        e.printStackTrace();
        flag = false;
    }
    return flag;
}
greeble31

'error'HTML5ビデオ要素にハンドラーを配置すると、このファイルで次のエラーが発生することがわかります(Chrome71)。

Error 3; details: PIPELINE_ERROR_DECODE: Failed to send audio packet for decoding: timestamp=0 duration=32000 size=2 side_data_size=0 is_key_frame=1 encrypted=0 discard_padding (us)=(0, 0)

(参考:同様のエラーがgithub説明されています)。

オーディオサンプルの場合、2バイトは少し小さいです。少し掘り下げてみると、これは実際にはオーディオトラックの「AudioSpecific Config」のコピーであることがわかります。これは、その情報が.mp4ヘッダーにすでに存在しているためです。タイムスタンプ0(最初のサンプル)でサンプルに複製されています。理由はわかりません。

setAudioEncoder();のドキュメントを確認することをお勧めします。あなたはそれを呼んでおらず、ドキュメントは次のように述べています:

このメソッドが呼び出されない場合、出力ファイルにはオーディオトラックが含まれません。

ただし、ファイルにはオーディオトラックが含まれています。したがって、これはもう少し調査する必要があるかもしれません。

編集

問題に対するこの新しい理解を考えると、最も適切な解決策は、AACストリームから最初のサンプルを強制的に削除することであるように思われます。あなたの「結合」コードでそれを行うかもしれません。私はAACTrackImplこのようにサブクラス化します:

AACTrackImpl aacTrack = new AACTrackImpl(new FileDataSourceImpl(aacPath)) {
    boolean mAltered = false;
    @Override
    List<Sample> getSamples() {
        List<Samples> samples = super.getSamples();
        if(!mAltered)
        {
            samples.remove(0);
            mAltered=true;
        }
        return samples;
    }
};

私はこのコードをテストしていません。非常にハックなソリューションであり、多くの仮定に依存しています。これは、AACトラック内のすべてのサンプルがたまたま同じ「期間」を持っているという事実を利用しています。それ以外の場合getSampleDurations()も、同様の手法を使用してオーバーライドする必要があります

サンプルを削除しましたが、タイムスタンプを変更しなかったため、すべてのオーディオが最大23ミリ秒シフトします。この場合、オーディオエンコーダが最初にこの動作を示した理由が正確にわからないため、これはタイミングの問題を引き起こしている、または問題を修正していると解釈できます。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

ラムダキャプチャリスト:オブジェクト全体をキャプチャしないと、オブジェクトのメンバーフィールドを値でキャプチャすることはできませんか?

分類Dev

ASP.NET MVCを使用して、WebRTCまたはブラウザーベースのキャプチャメカニズムからサーバーへのライブビデオWebカメラストリームの処理/受信

分類Dev

ドキュメントディレクトリにビデオを保存またはダウンロードして、ドキュメントディレクトリから再生することができません

分類Dev

AndroidのブラウザからHTMLをキャプチャできません

分類Dev

Androidスクリーンレコーディングのハウツー-ランドスケープレコーディング、ビデオレコーディングはフルスクリーンとパーシャルスクリーンで再生されます

分類Dev

プラグインからWebサービスへのSSL / TLSセキュアチャネルを作成できませんでした

分類Dev

キャプチャカードからリアルタイムビデオを取得できません

分類Dev

みなさん、こんにちは。スクリーンマネージャーでkivyでビデオを再生するにはどうすればよいですか?試しましたができませんでした

分類Dev

Ubuntu 18.04 はどのブラウザでもビデオやオーディオを再生できませんか?

分類Dev

ビデオをライブストリーミングし、ユーザーからの入力をキャプチャして、Raspberry PiRobotに送信します

分類Dev

ダウンロードしたビデオをiOSアプリで再生できません

分類Dev

ルート(サービスまたはバックグラウンドスレッド)を使用したAndroidスクリーンキャプチャ

分類Dev

DVD/Blu-ray HDMI OUT を HDMI キャプチャ カードに接続して、コンピュータのソフトウェアでビデオをデコードできるようにすべきではありませんか?

分類Dev

FirebaseデータからオブジェクトをPOJOにキャストできませんでした

分類Dev

MediaRecorderからサーバーにチャンクを送信し、ブラウザーで再生します

分類Dev

コンピューターのカメラでキャプチャしたビデオをWebサイトからサーバーに送信する

分類Dev

コンポーザーを使用してビジネス ネットワークをハイパーレジャー ファブリック ベータにデプロイできませんでした

分類Dev

Seleniumスクリーンキャプチャ-画像は利用できません

分類Dev

Android用YouTubeプレーヤーでビデオ再生アクションをキャプチャする方法

分類Dev

グーグルクラウド機能は投稿リクエストをキャプチャできません

分類Dev

Exchangeコマンドレットから警告をキャプチャ/リダイレクトできません

分類Dev

Androidデバイスはビーコンをスキャンできません

分類Dev

C ++ 11:ラムダ関数でクラスのメンバーをキャプチャしようとすると `this`をキャプチャできません

分類Dev

ジャクソンを使用して、オブジェクトの値(なしdelegate-またはプロパティベースクリエイター)からデシリアライズすることはできません

分類Dev

android 8(oreo)でaltbeaconライブラリを使用すると、バックグラウンドビーコンスキャンが機能しません

分類Dev

MPVでリアとフロントのドライブレコーダービデオのプレイリストを再生できますか?

分類Dev

QRをスキャンした後に表示されるプレーンテキストをクリック可能にして、ユーザーをブラウザにリダイレクトするにはどうすればよいですか?

分類Dev

レンダリング中にTypeErrorをキャッチしました: 'int'オブジェクトはdjangoテンプレートで反復できません

分類Dev

Perl、リターンコードをキャプチャできませんか?

Related 関連記事

  1. 1

    ラムダキャプチャリスト:オブジェクト全体をキャプチャしないと、オブジェクトのメンバーフィールドを値でキャプチャすることはできませんか?

  2. 2

    ASP.NET MVCを使用して、WebRTCまたはブラウザーベースのキャプチャメカニズムからサーバーへのライブビデオWebカメラストリームの処理/受信

  3. 3

    ドキュメントディレクトリにビデオを保存またはダウンロードして、ドキュメントディレクトリから再生することができません

  4. 4

    AndroidのブラウザからHTMLをキャプチャできません

  5. 5

    Androidスクリーンレコーディングのハウツー-ランドスケープレコーディング、ビデオレコーディングはフルスクリーンとパーシャルスクリーンで再生されます

  6. 6

    プラグインからWebサービスへのSSL / TLSセキュアチャネルを作成できませんでした

  7. 7

    キャプチャカードからリアルタイムビデオを取得できません

  8. 8

    みなさん、こんにちは。スクリーンマネージャーでkivyでビデオを再生するにはどうすればよいですか?試しましたができませんでした

  9. 9

    Ubuntu 18.04 はどのブラウザでもビデオやオーディオを再生できませんか?

  10. 10

    ビデオをライブストリーミングし、ユーザーからの入力をキャプチャして、Raspberry PiRobotに送信します

  11. 11

    ダウンロードしたビデオをiOSアプリで再生できません

  12. 12

    ルート(サービスまたはバックグラウンドスレッド)を使用したAndroidスクリーンキャプチャ

  13. 13

    DVD/Blu-ray HDMI OUT を HDMI キャプチャ カードに接続して、コンピュータのソフトウェアでビデオをデコードできるようにすべきではありませんか?

  14. 14

    FirebaseデータからオブジェクトをPOJOにキャストできませんでした

  15. 15

    MediaRecorderからサーバーにチャンクを送信し、ブラウザーで再生します

  16. 16

    コンピューターのカメラでキャプチャしたビデオをWebサイトからサーバーに送信する

  17. 17

    コンポーザーを使用してビジネス ネットワークをハイパーレジャー ファブリック ベータにデプロイできませんでした

  18. 18

    Seleniumスクリーンキャプチャ-画像は利用できません

  19. 19

    Android用YouTubeプレーヤーでビデオ再生アクションをキャプチャする方法

  20. 20

    グーグルクラウド機能は投稿リクエストをキャプチャできません

  21. 21

    Exchangeコマンドレットから警告をキャプチャ/リダイレクトできません

  22. 22

    Androidデバイスはビーコンをスキャンできません

  23. 23

    C ++ 11:ラムダ関数でクラスのメンバーをキャプチャしようとすると `this`をキャプチャできません

  24. 24

    ジャクソンを使用して、オブジェクトの値(なしdelegate-またはプロパティベースクリエイター)からデシリアライズすることはできません

  25. 25

    android 8(oreo)でaltbeaconライブラリを使用すると、バックグラウンドビーコンスキャンが機能しません

  26. 26

    MPVでリアとフロントのドライブレコーダービデオのプレイリストを再生できますか?

  27. 27

    QRをスキャンした後に表示されるプレーンテキストをクリック可能にして、ユーザーをブラウザにリダイレクトするにはどうすればよいですか?

  28. 28

    レンダリング中にTypeErrorをキャッチしました: 'int'オブジェクトはdjangoテンプレートで反復できません

  29. 29

    Perl、リターンコードをキャプチャできませんか?

ホットタグ

アーカイブ