2017-07-10 1 views
0

Ich versuche MediaCodec und MediaMuxer zu verwenden, um eine Reihe von JPEGs in ein mp4 zu ändern.ARGB kann nicht in YUV420Planar geändert werden

Egal was ich mache, ich bekomme immer einen grünen statischen Bildschirm als Ausgabe auf dem MP4.

-Code folgt:

public class AvcEncoder 
{ 
    public bool CanEncode = true; 

    MediaCodec codec; 
    MediaMuxer muxer; 
    MediaFormat format; 
    public AvcEncoder() 
    { 
     codec = MediaCodec.CreateEncoderByType("video/avc"); 
     format = MediaFormat.CreateVideoFormat("video/avc", 720, 480); 
     format.SetInteger(MediaFormat.KeyBitRate, 700000); 
     format.SetInteger(MediaFormat.KeyFrameRate, 10); 
     format.SetInteger(MediaFormat.KeyColorFormat, (int)Android.Media.MediaCodecCapabilities.Formatyuv420planar); 
     format.SetInteger(MediaFormat.KeyIFrameInterval, 5); 
     codec.Configure(format, null, null, MediaCodecConfigFlags.Encode); 
     codec.Start(); 
     Java.IO.File f = new Java.IO.File(Android.OS.Environment.ExternalStorageDirectory, "Parkingdom"); 
     if (!f.Exists()) 
     { 
      f.Mkdirs(); 
     } 
     muxer = new MediaMuxer(f.ToString() + "/test.mp4", MuxerOutputType.Mpeg4); 
    } 

    public void EncodeFrame(Bitmap image) 
    { 
     int mWidth = image.Width; 
     int mHeight = image.Height; 

     int[] mIntArray = new int[mWidth * mHeight]; 

     // Copy pixel data from the Bitmap into the 'intArray' array 
     image.GetPixels(mIntArray, 0, mWidth, 0, 0, mWidth, mHeight); 
     byte[] byteArray = new byte[mWidth * mHeight * 3/2]; 
     // Call to encoding function : convert intArray to Yuv Binary data 
     EncodeYUV420P(byteArray, mIntArray, mWidth, mHeight); 


     using (var stream = new MemoryStream()) 
     { 
      image.Compress(Bitmap.CompressFormat.Png, 100, stream); 
      byteArray = stream.ToArray(); 
     } 

     int inputBufferIndex = codec.DequeueInputBuffer(-1); 
     if (inputBufferIndex >= 0) 
     { 
      ByteBuffer buffer = codec.GetInputBuffer(inputBufferIndex); 
      buffer.Clear(); 
      buffer.Put(byteArray); 
      codec.QueueInputBuffer(inputBufferIndex, 0, byteArray.Length, 0, 0); 
     } 
    } 

    public void SaveMp4() 
    { 

     CanEncode = false; 
     bool running = true; 
     MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); 
     int track = -1; 

     while (running) 
     { 
      int index = codec.DequeueOutputBuffer(bufferInfo, 10000); 
      if (index == (int)MediaCodecInfoState.OutputFormatChanged) 
      { 
       MediaFormat format = codec.OutputFormat; 
       track = muxer.AddTrack(format); 
       muxer.Start(); 
      } 
      else if (index == (int)MediaCodecInfoState.TryAgainLater) 
      { 
       break; 
      } 
      else if (index >= 0) 
      { 
       if ((bufferInfo.Flags & MediaCodecBufferFlags.CodecConfig) != 0) 
       { 
        bufferInfo.Size = 0; 
       } 


       if (track != -1) 
       { 
        ByteBuffer outBuffer = codec.GetOutputBuffer(index); 
        outBuffer.Position(bufferInfo.Offset); 
        outBuffer.Limit(bufferInfo.Offset + bufferInfo.Size); 
        muxer.WriteSampleData(track, outBuffer, bufferInfo); 
        codec.ReleaseOutputBuffer(index, false); 
       } 
      } 
     } 

     codec.Stop(); 
     codec.Release(); 
     muxer.Stop(); 
     muxer.Release(); 

     CanEncode = true; 

    } 

    void EncodeYUV420P(byte[] yuv420p, int[] argb, int width, int height) 
    { 
     int frameSize = width * height; 
     int chromasize = frameSize/4; 


     int yIndex = 0; 
     int uIndex = frameSize; 
     int vIndex = frameSize + chromasize; 

     int a, R, G, B, Y, U, V; 
     int index = 0; 
     for (int j = 0; j < height; j++) 
     { 
      for (int i = 0; i < width; i++) 
      { 

       a = (int)(argb[index] & 0xff000000) >> 24; // a is not used obviously 
       R = (argb[index] & 0xff0000) >> 16; 
       G = (argb[index] & 0xff00) >> 8; 
       B = (argb[index] & 0xff) >> 0; 

       Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; 
       U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; 
       V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; 


       yuv420p[yIndex++] = (byte)((Y < 0) ? 0 : ((Y > 255) ? 255 : Y)); 
       if (j % 2 == 0 && index % 2 == 0) 
       { 
        yuv420p[uIndex++] = (byte)((U < 0) ? 0 : ((U > 255) ? 255 : U)); 
        yuv420p[vIndex++] = (byte)((V < 0) ? 0 : ((V > 255) ? 255 : V)); 
       } 

       index++; 
      } 
     } 
    } 
} 

Jedes Mal, wenn eine neue JPEG erzeugt wird „EncodeFrame“ genannt wird, die angeblich in ein YUV420Planar Format für den Media-Codec zu ändern. Der Codec, mit dem ich teste, unterstützt Semiplanar nicht.

+0

ich verwende ich Xamarin vergessen zu erwähnen, das ist, warum der Code in C# ist – CurtDotNet

+0

ich, dass ich meine byteArray mit altem Code nur realisiert 'mit (var stream = new Memory()) { Bild wurde überschrieben wird. Komprimieren (Bitmap.CompressFormat.Png, 100, stream); /byteArray = stream.ToArray(); } ' Allerdings funktioniert der Code immer noch nicht nach dem Entfernen – CurtDotNet

Antwort

0

Falls jemand über das kommt später änderte ich

EncodeFrame eine Fläche stattdessen zu verwenden und nur DrawBitmap verwendet().

Es ist langsamer als die Byte-Kopie, aber funktioniert für meine Zwecke.

Verwandte Themen