2017-07-10 4 views
0

J'essaye d'utiliser MediaCodec et MediaMuxer pour changer une série de JPEG dans un mp4.Impossible de changer ARGB en YUV420Planar

Peu importe ce que je fais, je reçois toujours un écran de statistiques vertes en sortie sur le MP4.

Code suit:

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++; 
      } 
     } 
    } 
} 

Chaque fois qu'un nouveau jpeg est généré « EncodeFrame » est appelé qui est censé être le changer dans un format YUV420Planar pour le codec multimédia. Le codec avec lequel je teste ne supporte pas semiplanar.

+0

j'oublié de mentionner que je utilise Xamarin, c'est pourquoi le code est en C# – CurtDotNet

+0

Je viens de réaliser que j'Écrasement des mon byteArray avec l'ancien code 'l'aide (flux var = new MemoryStream()) { image. Compresser (Bitmap.CompressFormat.Png, 100, flux); /byteArray = stream.ToArray(); } ' Cependant, le code ne fonctionne toujours pas après l'avoir supprimé – CurtDotNet

Répondre

0

Dans le cas où quelqu'un vient dans cette suite je me

EncodeFrame utiliser une surface au lieu et juste utilisé DrawBitmap().

Il est plus lent que la copie d'octets, mais fonctionne pour mes objectifs.