Exemple #1
0
        protected override async void Run()
        {
            try
            {
                running = true;
                var finfo = new System.IO.FileInfo(FilePlayer.SAMPLE);//FilePlayer.dir + "decode.out");
                var fs = finfo.OpenRead();
                int bytes, count, inIndex = 0;
                int buffSize = TsPacket.PacketLength * 4;//simulate multiple TS packets grouped into a single UDP packet
                var buff     = new byte[buffSize];
                var ts       = new MpegTS.TsPacket(buff);
                buffEx = new BufferExtractor();
                //buffEx.SampleReady += BuffEx_SampleReady;
                bool eof = false;


                using (info)
                    using (decoder)
                        using (fs)
                        {
                            count = 0;
                            Log.Debug(TAG, "looking for format info");

                            ////look for the format info.
                            //do
                            //{
                            //    bytes = await fs.ReadAsync(buff, 0, buff.Length).ConfigureAwait(false);

                            //    Log.Debug(TAG, "PID: " + string.Format("{0}", ts.PID));

                            //} while (BitConverter.ToInt32(buff, formatStartI) != formatStartVal);

                            //Log.Debug(TAG, "found format info");

                            //var tmpB = new byte[23 + 8];
                            //System.Buffer.BlockCopy(buff, formatStartI - 4, tmpB, 0, tmpB.Length);

                            InitializeDecoder();

                            fs.Position = 0;//reset

                            sw.Restart();
                            //bool started = false;
                            do
                            {
                                ++count;
                                try
                                {
                                    while (fs.CanRead && buffEx.SampleCount == 0)
                                    {
                                        if (fs.Length - fs.Position < buffSize)
                                        {
                                            eof = true;
                                            break;//we're @ EOF
                                        }

                                        //we need a new buffer every loop!
                                        buff  = new byte[buffSize];
                                        bytes = await fs.ReadAsync(buff, 0, buff.Length)
                                                .ConfigureAwait(false);

                                        //push the raw data to our custom extractor
                                        if (!buffEx.AddRaw(buff))
                                        {
                                            Log.Debug("ExtractorActivity,   ", " ----------bad TS packet!");

                                            //find next sync byte and try again
                                            fs.Position -= buff.Length
                                                           - buff.ToList().IndexOf(MpegTS.TsPacket.SyncByte);
                                        }
                                    }

                                    if (!fs.CanRead || eof)
                                    {
                                        break;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Log.Error("ExtractorActivity error: ", ex.ToString());
                                }

                                //get the raw video stream, stripped of Mpeg TS headers
                                var sample = buffEx.DequeueNextSample();
                                Log.Debug("ExtractorActivity, sampleSize: ", sample.Length.ToString());

                                //var outputBuffers = decoder.GetOutputBuffers();

                                //get a input buffer index from the decoder for input
                                inIndex = decoder.DequeueInputBuffer(10000);


                                if (inIndex >= 0)
                                {
                                    //get the re-assembled video data from the extractor
                                    using (var b = Java.Nio.ByteBuffer.Wrap(sample.Buffer))
                                    {
                                        var inB = inputBuffers[inIndex];
                                        //*************
                                        //THE BUFFER *******MUST********* be CLEARED before each write,
                                        //else when the buffers start getting recycled, the decoder will
                                        //read past the end of the current data into old data!
                                        //This may cause tearing of the picture, or even a complete
                                        //crash of the app from internal errors in native decoder code!!!!!
                                        inB.Clear();
                                        inB.Put(b);//put data into the decoder's native buffer

                                        //tell the decoder about the new data in the buffer
                                        decoder.QueueInputBuffer(inIndex, 0, b.Limit(), 0, MediaCodecBufferFlags.None);
                                    }//  b.Dispose();//clean up
                                }
                                //else
                                //    continue;//we don't have a full video frame, look for more.

                                //check decoder output/state
                                int outIndex = decoder.DequeueOutputBuffer(info, 10000);

                                switch ((Android.Media.MediaCodecInfoState)outIndex)
                                {
                                case MediaCodecInfoState.OutputBuffersChanged:
                                    Android.Util.Log.Debug("DecodeActivity",
                                                           MediaCodecInfoState.OutputBuffersChanged.ToString());
                                    outputBuffers = decoder.GetOutputBuffers();
                                    break;

                                case MediaCodecInfoState.OutputFormatChanged:

                                    Android.Util.Log.Debug("DecodeActivity", "New format " + decoder.OutputFormat);//.GetOutputFormat(outIndex));
                                    break;

                                case MediaCodecInfoState.TryAgainLater:
                                    Android.Util.Log.Debug("DecodeActivity", "dequeueOutputBuffer timed out!");
                                    break;

                                default:
                                    var buffer = outputBuffers[outIndex];// decoder.GetOutputBuffer(outIndex);
                                    Android.Util.Log.Verbose("DecodeActivity", "render the buffer, " + buffer);

                                    //bool gcDone = false;
                                    // We use a very simple clock to keep the video FPS, or the video
                                    // playback will be too fast
                                    //This causes the next frame to not be rendered too quickly.
                                    while (info.PresentationTimeUs / 1000 > sw.ElapsedMilliseconds)
                                    {
                                        await Task.Delay(10).ConfigureAwait(false);
                                    }
                                    //the decoder won't advance without this...
                                    //must be called before the next decoder.dequeue call
                                    decoder.ReleaseOutputBuffer(outIndex, true);
                                    break;
                                }
                            } while (fs.CanRead && running);

                            Log.Debug("DecodeActivity", MediaCodecBufferFlags.EndOfStream.ToString());
                            try
                            {
                                decoder.QueueInputBuffer(inIndex, 0, 0, 0, MediaCodecBufferFlags.EndOfStream);
                            }
                            catch (Exception ex)
                            {
                                Log.Debug("DecodeActivity", "error closing decoder!");
                            }
                        }//dispose filestream,decoder, info
            }
            catch (Exception ex)
            {
                Log.Debug(this.GetType().Name, ex.ToString());
            }
            info    = null;
            decoder = null;
        }
Exemple #2
0
        override public async void Run()
        {
            //Android.Media.MediaExtractor extractor;

            Android.Media.MediaCodec decoder = null;

            using (var extractor = new Android.Media.MediaExtractor())
            //using (Android.Media.MediaCodec decoder = null)
            {
                //extractor = new Android.Media.MediaExtractor();
                try
                {
                    await extractor.SetDataSourceAsync(SAMPLE).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    var s = ex.ToString();
                    return;
                }

                for (int i = 0; i < extractor.TrackCount; i++)
                {
                    var format = extractor.GetTrackFormat(i);

                    Log.Debug("Format info: ", format.ToString());

                    String mime = format.GetString(Android.Media.MediaFormat.KeyMime);
                    if (mime.StartsWith("video/"))
                    {
                        Log.Debug("Format mime: ", mime);
                        //Log.Debug("Format " + MediaFormat.KeyMaxInputSize + ": ",
                        //            format.GetInteger(MediaFormat.KeyMaxInputSize).ToString());
                        Log.Debug("Format " + MediaFormat.KeyWidth + ": ",
                                  format.GetInteger(MediaFormat.KeyWidth).ToString());
                        Log.Debug("Format " + MediaFormat.KeyHeight + ": ",
                                  format.GetInteger(MediaFormat.KeyHeight).ToString());

                        PrintFormatInfo(format);

                        extractor.SelectTrack(i);
                        //decoder = Android.Media.MediaCodec.CreateDecoderByType(mime);
                        //this is where the Xamarin Android VM dies.
                        //decoder.Configure(format, surface, null, 0);
                        break;
                    }
                }

                //if (decoder == null)
                //{
                //    Android.Util.Log.Error("DecodeActivity", "Can't find video info!");
                //    return;//can't continue...
                //}
                var f = new Java.IO.File(dir + "decode.out");
                if (f.Exists())
                {
                    f.Delete();
                }

                f.CreateNewFile();

                var f2 = new Java.IO.File(dir + "decode2.out");
                if (f2.Exists())
                {
                    f2.Delete();
                }

                f2.CreateNewFile();

                //open the file for our custom extractor
                var inInfo = new System.IO.FileInfo(SAMPLE);
                if (!inInfo.Exists)
                {
                    Log.Error("input file not found!", inInfo.FullName);
                    return;
                }

                using (var inStream = inInfo.OpenRead())
                    using (var fs2 = new Java.IO.FileOutputStream(f2))   //get an output stream
                        using (var fs = new Java.IO.FileOutputStream(f)) //get an output stream
                        {
                            //var inputBuffers = decoder.GetInputBuffers();
                            //var outputBuffers = decoder.GetOutputBuffers();
                            var  info = new Android.Media.MediaCodec.BufferInfo();
                            bool started = false, isEOS = false;
                            var  sw      = new System.Diagnostics.Stopwatch();
                            long startMs = sw.ElapsedMilliseconds;
                            sw.Start();
                            byte[] peekBuf = new byte[188];
                            //for dumping the sample into instead of the decoder.
                            var buffer = Java.Nio.ByteBuffer.Allocate(165000);// decoder.GetInputBuffer(inIndex);
                            var buffEx = new BufferExtractor();
                            var tmpB   = new byte[20000];


                            while (!interrupted)
                            {
                                //sw.Restart();

                                if (!isEOS)
                                {
                                    int inIndex = 1;// decoder.DequeueInputBuffer(10000);
                                    if (inIndex >= 0)
                                    {
                                        buffer.Position(0);//reset the buffer
                                        if (buffer.Position() != 0)
                                        {
                                            Log.Debug("inBuff.Position: ", buffer.Position().ToString());
                                        }
                                        Log.Debug("inBuff: ", buffer.ToString());

                                        int sampleSize = extractor.ReadSampleData(buffer, 0);
                                        if (sampleSize < 0)
                                        {
                                            // We shouldn't stop the playback at this point, just pass the EOS
                                            // flag to decoder, we will get it again from the
                                            // dequeueOutputBuffer
                                            Log.Debug("DecodeActivity", MediaCodecBufferFlags.EndOfStream.ToString());
                                            //decoder.QueueInputBuffer(inIndex, 0, 0, 0, MediaCodecBufferFlags.EndOfStream);
                                            isEOS = true;
                                        }
                                        else
                                        {
                                            if (peekBuf.Length < sampleSize)
                                            {
                                                peekBuf = new byte[sampleSize];
                                            }
                                            peekBuf.Initialize(); //clear old data.
                                            buffer.Get(peekBuf);
                                            buffer.Position(0);   //reset for the decoder

                                            for (int i = 4; i < peekBuf.Length; ++i)
                                            {
                                                if (peekBuf[i] == 0x01 &&
                                                    peekBuf[i - 1] == 0x00 &&
                                                    peekBuf[i - 2] == 0x00 &&
                                                    peekBuf[i - 3] == 0x00)
                                                {
                                                    Log.Debug("Found h264 start code: ",
                                                              string.Format("i={0} of {1}", i, sampleSize));
                                                }
                                            }

                                            Log.Debug("ExtractorActivity, sampleSize: ", sampleSize.ToString());

                                            if (!started)//get your parser synced with theirs
                                            {
                                                do
                                                {
                                                    peekBuf = new byte[188];
                                                    await inStream.ReadAsync(peekBuf, 0, peekBuf.Length)
                                                    .ConfigureAwait(false);

                                                    buffEx.AddRaw(peekBuf);

                                                    if (buffEx.outBuffers.Count > 0 &&
                                                        buffEx.outBuffers.Peek().GetPayload().Length != sampleSize)
                                                    {
                                                        buffEx.outBuffers.Dequeue();//throw this one away
                                                    }
                                                } while (buffEx.outBuffers.Count == 0);
                                                started = true;
                                            }
                                            else
                                            {
                                                do
                                                {
                                                    peekBuf = new byte[188];
                                                    await inStream.ReadAsync(peekBuf, 0, peekBuf.Length)
                                                    .ConfigureAwait(false);

                                                    buffEx.AddRaw(peekBuf);
                                                } while (buffEx.outBuffers.Count == 0);
                                                started = true;
                                            }

                                            //write out the vid data.
                                            buffer.Limit(sampleSize);
                                            buffer.Position(0);
                                            //if (tmpB.Length < sampleSize)
                                            tmpB = new byte[sampleSize];

                                            buffer.Get(tmpB);
                                            fs.Write(tmpB);

                                            buffer.Limit(buffer.Capacity());//reset the limit for next sample
                                            buffer.Position(0);

                                            fs2.Write(buffEx.outBuffers.Dequeue().GetPayload());

                                            if (!inStream.CanRead)
                                            {
                                                isEOS = true;//end of stream.
                                            }
                                            //decoder.QueueInputBuffer(inIndex, 0, sampleSize, extractor.SampleTime, 0);
                                            await extractor.AdvanceAsync().ConfigureAwait(false);

                                            //extractor.AdvanceAsync();
                                        }
                                    }
                                }


                                // All decoded frames have been rendered, we can stop playing now
                                if ((info.Flags & MediaCodecBufferFlags.EndOfStream) != 0)
                                {
                                    Android.Util.Log.Debug("DecodeActivity",
                                                           MediaCodecBufferFlags.EndOfStream.ToString());
                                    break;
                                }
                            }

                            //decoder.Stop();
                        }
            }
        }