Decodifica nuovamente il video e l'encoding da Mediacodec ottiene un file danneggiato

Sto cercando di implementare https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java ma modificando l'origine utilizzando un file video mp4. Il tipo mime è video / avc, bitrate 288kbps, iframeinterval 100, width: 176, altezza: 144. La dimensione del file è di 6MB. Quando decodisco il video e metto il frame nella superficie di output, posso salvare il fotogramma su una bitmap e vedere la cornice grande. Ma alla fine, dopo la codifica (con gli stessi parametri del video originale), ottengo un file da 700kb e non riesco a vedere il video (potrebbe essere un file danneggiato).

extractor = new MediaExtractor(); extractor.SetDataSource(filePath); for (int i = 0; i < extractor.TrackCount; i++) { inputFormat = extractor.GetTrackFormat(i); string mime = inputFormat.GetString(MediaFormat.KeyMime); if (mime.StartsWith("video/")) { extractor.SelectTrack(i); mimeType = mime; break; } } mWidth = inputFormat.GetInteger(MediaFormat.KeyWidth); mHeight = inputFormat.GetInteger(MediaFormat.KeyHeight); // Create an encoder format that matches the input format. (Might be able to just // re-use the format used to generate the video, since we want it to be the same.) MediaFormat outputFormat = MediaFormat.CreateVideoFormat(mimeType, mWidth, mHeight); outputFormat.SetInteger(MediaFormat.KeyColorFormat, (int)MediaCodecCapabilities.Formatsurface); outputFormat.SetInteger(MediaFormat.KeyBitRate, 288000); outputFormat.SetInteger(MediaFormat.KeyFrameRate, inputFormat.GetInteger(MediaFormat.KeyFrameRate)); outputFormat.SetInteger(MediaFormat.KeyIFrameInterval, 100); outputData.setMediaFormat(outputFormat); encoder = MediaCodec.CreateEncoderByType(mimeType); encoder.Configure(outputFormat, null, null, MediaCodecConfigFlags.Encode); inputSurface = new InputSurface(encoder.CreateInputSurface()); inputSurface.makeCurrent(); encoder.Start(); // OutputSurface uses the EGL context created by InputSurface. decoder = MediaCodec.CreateDecoderByType(mimeType); outputSurface = new OutputSurface(); outputSurface.changeFragmentShader(FRAGMENT_SHADER); decoder.Configure(inputFormat, outputSurface.getSurface(), null, 0); decoder.Start(); editVideoData2(extractor, decoder, outputSurface, inputSurface, encoder, outputData); 

e la parte di codifica di decodifica:

  • Come get le coordinate GPS each minuto in Android?
  • Problema con android MediaRecorder setVideoSize ()
  • Come impostare il cursore a destra (EditText)?
  • Android Gradle Duplicare i file copiati in APK META-INF / license.txt
  • Frammenti di Android. Sostenere un'AsyncTask durante la rotazione dello schermo o la modifica della configuration
  • Cosa fare con AsyncTask in onPause ()?
  •   while (!outputDone) { if (VERBOSE) Log.Debug(TAG, "edit loop"); // Feed more data to the decoder. if (!inputDone) { int inputBufIndex = decoder.DequeueInputBuffer(TIMEOUT_USEC); if (inputBufIndex >= 0) { ByteBuffer buffer = decoderInputBuffers[inputBufIndex]; int sampleSize = extractor.ReadSampleData(buffer, 0); if (sampleSize < 0) { inputChunk++; // End of stream -- send empty frame with EOS flag set. decoder.QueueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodecBufferFlags.EndOfStream); inputDone = true; if (VERBOSE) Log.Debug(TAG, "sent input EOS (with zero-length frame)"); } else { // Copy a chunk of input to the decoder. The first chunk should have // the BUFFER_FLAG_CODEC_CONFIG flag set. buffer.Clear(); decoder.QueueInputBuffer(inputBufIndex, 0, sampleSize, extractor.SampleTime, 0); extractor.Advance(); inputChunk++; } } else { if (VERBOSE) Log.Debug(TAG, "input buffer not available"); } } // Assume output is available. Loop until both assumptions are false. bool decoderOutputAvailable = !decoderDone; bool encoderOutputAvailable = true; while (decoderOutputAvailable || encoderOutputAvailable) { // Start by draining any pending output from the encoder. It's importnt to // do this before we try to stuff any more data in. int encoderStatus = encoder.DequeueOutputBuffer(info, TIMEOUT_USEC); if (encoderStatus == (int)MediaCodecInfoState.TryAgainLater) { // no output available yet if (VERBOSE) Log.Debug(TAG, "no output from encoder available"); encoderOutputAvailable = false; } else if (encoderStatus == (int)MediaCodecInfoState.OutputBuffersChanged) { encoderOutputBuffers = encoder.GetOutputBuffers(); if (VERBOSE) Log.Debug(TAG, "encoder output buffers changed"); } else if (encoderStatus == (int)MediaCodecInfoState.OutputFormatChanged) { MediaFormat newFormat = encoder.OutputFormat; if (VERBOSE) Log.Debug(TAG, "encoder output format changed: " + newFormat); } else if (encoderStatus < 0) { Log.Error(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus); } else { // encoderStatus >= 0 ByteBuffer encodedData = encoderOutputBuffers[encoderStatus]; if (encodedData == null) { Log.Error(TAG,"encoderOutputBuffer " + encoderStatus + " was null"); } // Write the data to the output "file". if (info.Size != 0) { encodedData.Position(info.Offset); encodedData.Limit(info.Offset + info.Size); byte[] data = new byte[encodedData.Remaining()]; encodedData.Get(data); fStream.Write(data, 0, data.Length); // outputData.addChunk(encodedData, (int)info.Flags, info.PresentationTimeUs); outputCount++; if (VERBOSE) Log.Debug(TAG, "encoder output " + info.Size + " bytes"); } outputDone = (info.Flags & MediaCodecBufferFlags.EndOfStream) != 0; encoder.ReleaseOutputBuffer(encoderStatus, false); } if (encoderStatus != (int)MediaCodecInfoState.TryAgainLater) { // Continue attempts to drain output. continue; } // Encoder is drained, check to see if we've got a new frame of output from // the decoder. (The output is going to a Surface, rather than a ByteBuffer, // but we still get information through BufferInfo.) if (!decoderDone) { int decoderStatus = decoder.DequeueOutputBuffer(info, TIMEOUT_USEC); if (decoderStatus == (int)MediaCodecInfoState.TryAgainLater) { // no output available yet if (VERBOSE) Log.Debug(TAG, "no output from decoder available"); decoderOutputAvailable = false; } else if (decoderStatus == (int)MediaCodecInfoState.OutputBuffersChanged) { //decoderOutputBuffers = decoder.GetOutputBuffers(); if (VERBOSE) Log.Debug(TAG, "decoder output buffers changed (we don't care)"); } else if (decoderStatus == (int)MediaCodecInfoState.OutputFormatChanged) { // expected before first buffer of data MediaFormat newFormat = decoder.OutputFormat; if (VERBOSE) Log.Debug(TAG, "decoder output format changed: " + newFormat); } else if (decoderStatus < 0) { Log.Error(TAG,"unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus); } else { // decoderStatus >= 0 if (VERBOSE) Log.Debug(TAG, "surface decoder given buffer " + decoderStatus + " (size=" + info.Size + ")"); // The ByteBuffers are null references, but we still get a nonzero // size for the decoded data. bool doRender = (info.Size != 0); // As soon as we call releaseOutputBuffer, the buffer will be forwarded // to SurfaceTexture to convert to a texture. The API doesn't // guarantee that the texture will be available before the call // returns, so we need to wait for the onFrameAvailable callback to // fire. If we don't wait, we risk rendering from the previous frame. decoder.ReleaseOutputBuffer(decoderStatus, doRender); if (doRender) { // This waits for the image and renders it after it arrives. if (VERBOSE) Log.Debug(TAG, "awaiting frame"); outputSurface.awaitNewImage(); outputSurface.drawImage(); outputSurface.saveFrame(Android.OS.Environment.ExternalStorageDirectory + "/test.jpg", mWidth, mHeight); // Send it to the encoder. inputSurface.setPresentationTime(info.PresentationTimeUs * 1000); if (VERBOSE) Log.Debug(TAG, "swapBuffers"); inputSurface.swapBuffers(); } if ((info.Flags & MediaCodecBufferFlags.EndOfStream) != 0) { // forward decoder EOS to encoder if (VERBOSE) Log.Debug(TAG, "signaling input EOS"); if (WORK_AROUND_BUGS) { // Bail early, possibly dropping a frame. return; } else { encoder.SignalEndOfInputStream(); } } } } } } if (inputChunk != outputCount) { throw new RuntimeException("frame lost: " + inputChunk + " in, " + outputCount + " out"); } fStream.Close(); 

    Se ottengo la cornice in un'image e posso vederlo okay, suppongo che il frame sia ok per OutputSurface. E non vedo alcuna strana nella configuration dell'encoder. Potresti aiutarmi, alless dicendo che pensi di poter controllare? Grazie.

  • onAttach () non chiamato con setRetainInstance (true);
  • Ottenere le misure della window popup
  • Apri la pagina in Facebook, Twitter e Google Plus da un'altra applicazione - Android
  • errore nel call il servizio Web
  • Come aggiornare una vista nell'attività principale da un'adattatore?
  • login facebook in android LoginButton.setFragment
  • One Solution collect form web for “Decodifica nuovamente il video e l'encoding da Mediacodec ottiene un file danneggiato”

    Ho dimenticato di aggiungere il Mediamuxer come ha detto fadden. Se si modifica la parte fstream da un Mediamuxer writesampledata e si aggiungono le start() e stop() e le chiamate Adtrack() , sta funzionando perfettamente. Chiunque può vedere questo codice come esempio di codifica di decodifica. Grazie.

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.