Advertisement
filebot

FFmpegFrameGrabber for I-Frames

Dec 30th, 2013
591
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 22.22 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2009,2010,2011,2012,2013 Samuel Audet
  3.  *
  4.  * This file is part of JavaCV.
  5.  *
  6.  * JavaCV is free software: you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation, either version 2 of the License, or
  9.  * (at your option) any later version (subject to the "Classpath" exception
  10.  * as provided in the LICENSE.txt file that accompanied this code).
  11.  *
  12.  * JavaCV is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with JavaCV.  If not, see <http://www.gnu.org/licenses/>.
  19.  *
  20.  *
  21.  * Based on the avcodec_sample.0.5.0.c file available at
  22.  * http://web.me.com/dhoerl/Home/Tech_Blog/Entries/2009/1/22_Revised_avcodec_sample.c_files/avcodec_sample.0.5.0.c
  23.  * by Martin Böhme, Stephen Dranger, and David Hoerl
  24.  * as well as on the decoding_encoding.c file included in FFmpeg 0.11.1,
  25.  * which is covered by the following copyright notice:
  26.  *
  27.  * Copyright (c) 2001 Fabrice Bellard
  28.  *
  29.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  30.  * of this software and associated documentation files (the "Software"), to deal
  31.  * in the Software without restriction, including without limitation the rights
  32.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  33.  * copies of the Software, and to permit persons to whom the Software is
  34.  * furnished to do so, subject to the following conditions:
  35.  *
  36.  * The above copyright notice and this permission notice shall be included in
  37.  * all copies or substantial portions of the Software.
  38.  *
  39.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  40.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  41.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  42.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  43.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  44.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  45.  * THE SOFTWARE.
  46.  */
  47.  
  48. package ntu.vashj;
  49.  
  50. import static com.googlecode.javacv.cpp.avcodec.*;
  51. import static com.googlecode.javacv.cpp.avdevice.*;
  52. import static com.googlecode.javacv.cpp.avformat.*;
  53. import static com.googlecode.javacv.cpp.avutil.*;
  54. import static com.googlecode.javacv.cpp.opencv_core.*;
  55. import static com.googlecode.javacv.cpp.swscale.*;
  56.  
  57. import java.io.File;
  58. import java.nio.Buffer;
  59. import java.nio.ByteBuffer;
  60.  
  61. import com.googlecode.javacpp.BytePointer;
  62. import com.googlecode.javacpp.DoublePointer;
  63. import com.googlecode.javacpp.IntPointer;
  64. import com.googlecode.javacpp.Loader;
  65. import com.googlecode.javacpp.PointerPointer;
  66. import com.googlecode.javacv.Frame;
  67. import com.googlecode.javacv.FrameGrabber;
  68. import com.googlecode.javacv.cpp.avcodec.AVCodec;
  69. import com.googlecode.javacv.cpp.avcodec.AVCodecContext;
  70. import com.googlecode.javacv.cpp.avcodec.AVPacket;
  71. import com.googlecode.javacv.cpp.avcodec.AVPicture;
  72. import com.googlecode.javacv.cpp.avformat.AVFormatContext;
  73. import com.googlecode.javacv.cpp.avformat.AVInputFormat;
  74. import com.googlecode.javacv.cpp.avformat.AVStream;
  75. import com.googlecode.javacv.cpp.avutil.AVDictionary;
  76. import com.googlecode.javacv.cpp.avutil.AVFrame;
  77. import com.googlecode.javacv.cpp.avutil.AVRational;
  78. import com.googlecode.javacv.cpp.opencv_core.IplImage;
  79. import com.googlecode.javacv.cpp.swscale.SwsContext;
  80.  
  81. /**
  82.  *
  83.  * @author Samuel Audet
  84.  */
  85. public class FFmpegKeyFrameGrabber extends FrameGrabber {
  86.     public static String[] getDeviceDescriptions() throws Exception {
  87.         tryLoad();
  88.         throw new UnsupportedOperationException("Device enumeration not support by FFmpeg.");
  89.     }
  90.  
  91.     public static FFmpegFrameGrabber createDefault(File deviceFile) throws Exception {
  92.         return new FFmpegFrameGrabber(deviceFile);
  93.     }
  94.  
  95.     public static FFmpegFrameGrabber createDefault(String devicePath) throws Exception {
  96.         return new FFmpegFrameGrabber(devicePath);
  97.     }
  98.  
  99.     public static FFmpegFrameGrabber createDefault(int deviceNumber) throws Exception {
  100.         return null;
  101.     }
  102.  
  103.     private static Exception loadingException = null;
  104.  
  105.     public static void tryLoad() throws Exception {
  106.         if (loadingException != null) {
  107.             throw loadingException;
  108.         } else {
  109.             try {
  110.                 Loader.load(com.googlecode.javacv.cpp.avutil.class);
  111.                 Loader.load(com.googlecode.javacv.cpp.avcodec.class);
  112.                 Loader.load(com.googlecode.javacv.cpp.avformat.class);
  113.                 Loader.load(com.googlecode.javacv.cpp.avdevice.class);
  114.                 Loader.load(com.googlecode.javacv.cpp.swscale.class);
  115.             } catch (Throwable t) {
  116.                 if (t instanceof Exception) {
  117.                     throw loadingException = (Exception) t;
  118.                 } else {
  119.                     throw loadingException = new Exception("Failed to load " + FFmpegFrameGrabber.class, t);
  120.                 }
  121.             }
  122.         }
  123.     }
  124.  
  125.     static {
  126.         // Register all formats and codecs
  127.         avcodec_register_all();
  128.         avdevice_register_all();
  129.         av_register_all();
  130.         avformat_network_init();
  131.     }
  132.  
  133.     public FFmpegKeyFrameGrabber(File file) {
  134.         this(file.getAbsolutePath());
  135.     }
  136.  
  137.     public FFmpegKeyFrameGrabber(String filename) {
  138.         this.filename = filename;
  139.     }
  140.  
  141.     public void release() throws Exception {
  142.         synchronized (com.googlecode.javacv.cpp.avcodec.class) {
  143.             releaseUnsafe();
  144.         }
  145.     }
  146.  
  147.     public void releaseUnsafe() throws Exception {
  148.         if (pkt != null && pkt2 != null) {
  149.             if (pkt2.size() > 0) {
  150.                 av_free_packet(pkt);
  151.             }
  152.             pkt = pkt2 = null;
  153.         }
  154.  
  155.         // Free the RGB image
  156.         if (buffer_rgb != null) {
  157.             av_free(buffer_rgb);
  158.             buffer_rgb = null;
  159.         }
  160.         if (picture_rgb != null) {
  161.             avcodec_free_frame(picture_rgb);
  162.             picture_rgb = null;
  163.         }
  164.  
  165.         // Free the native format picture frame
  166.         if (picture != null) {
  167.             avcodec_free_frame(picture);
  168.             picture = null;
  169.         }
  170.  
  171.         // Close the video codec
  172.         if (video_c != null) {
  173.             avcodec_close(video_c);
  174.             video_c = null;
  175.         }
  176.  
  177.         // Free the audio samples frame
  178.         if (samples_frame != null) {
  179.             avcodec_free_frame(samples_frame);
  180.             samples_frame = null;
  181.         }
  182.  
  183.         // Close the audio codec
  184.         if (audio_c != null) {
  185.             avcodec_close(audio_c);
  186.             audio_c = null;
  187.         }
  188.  
  189.         // Close the video file
  190.         if (oc != null && !oc.isNull()) {
  191.             avformat_close_input(oc);
  192.             oc = null;
  193.         }
  194.  
  195.         if (img_convert_ctx != null) {
  196.             sws_freeContext(img_convert_ctx);
  197.             img_convert_ctx = null;
  198.         }
  199.  
  200.         got_frame = null;
  201.         return_image = null;
  202.         frameGrabbed = false;
  203.         frame = null;
  204.         timestamp = 0;
  205.         frameNumber = 0;
  206.     }
  207.  
  208.     @Override
  209.     protected void finalize() throws Throwable {
  210.         super.finalize();
  211.         release();
  212.     }
  213.  
  214.     private String filename;
  215.     private AVFormatContext oc;
  216.     private AVStream video_st, audio_st;
  217.     private AVCodecContext video_c, audio_c;
  218.     public AVFrame picture, picture_rgb;
  219.     private BytePointer buffer_rgb;
  220.     private AVFrame samples_frame;
  221.     private BytePointer[] samples_ptr;
  222.     private Buffer[] samples_buf;
  223.     private AVPacket pkt, pkt2;
  224.     private int sizeof_pkt;
  225.     private int[] got_frame;
  226.     private SwsContext img_convert_ctx;
  227.     private IplImage return_image;
  228.     private boolean frameGrabbed;
  229.     private Frame frame;
  230.  
  231.     @Override
  232.     public double getGamma() {
  233.         // default to a gamma of 2.2 for cheap Webcams, DV cameras, etc.
  234.         if (gamma == 0.0) {
  235.             return 2.2;
  236.         } else {
  237.             return gamma;
  238.         }
  239.     }
  240.  
  241.     @Override
  242.     public String getFormat() {
  243.         if (oc == null) {
  244.             return super.getFormat();
  245.         } else {
  246.             return oc.iformat().name().getString();
  247.         }
  248.     }
  249.  
  250.     @Override
  251.     public int getImageWidth() {
  252.         return return_image == null ? super.getImageWidth() : return_image.width();
  253.     }
  254.  
  255.     @Override
  256.     public int getImageHeight() {
  257.         return return_image == null ? super.getImageHeight() : return_image.height();
  258.     }
  259.  
  260.     @Override
  261.     public int getAudioChannels() {
  262.         return audio_c == null ? super.getAudioChannels() : audio_c.channels();
  263.     }
  264.  
  265.     @Override
  266.     public int getPixelFormat() {
  267.         if (imageMode == ImageMode.COLOR || imageMode == ImageMode.GRAY) {
  268.             if (pixelFormat == AV_PIX_FMT_NONE) {
  269.                 return imageMode == ImageMode.COLOR ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_GRAY8;
  270.             } else {
  271.                 return pixelFormat;
  272.             }
  273.         } else if (video_c != null) { // RAW
  274.             return video_c.pix_fmt();
  275.         } else {
  276.             return super.getPixelFormat();
  277.         }
  278.     }
  279.  
  280.     @Override
  281.     public double getFrameRate() {
  282.         if (video_st == null) {
  283.             return super.getFrameRate();
  284.         } else {
  285.             AVRational r = video_st.r_frame_rate();
  286.             return (double) r.num() / r.den();
  287.         }
  288.     }
  289.  
  290.     @Override
  291.     public int getSampleFormat() {
  292.         return audio_c == null ? super.getSampleFormat() : audio_c.sample_fmt();
  293.     }
  294.  
  295.     @Override
  296.     public int getSampleRate() {
  297.         return audio_c == null ? super.getSampleRate() : audio_c.sample_rate();
  298.     }
  299.  
  300.     @Override
  301.     public void setFrameNumber(int frameNumber) throws Exception {
  302.         // best guess, AVSEEK_FLAG_FRAME has not been implemented in FFmpeg...
  303.         setTimestamp(Math.round(1000000L * frameNumber / getFrameRate()));
  304.     }
  305.  
  306.     @Override
  307.     public void setTimestamp(long timestamp) throws Exception {
  308.         int ret;
  309.         if (oc == null || video_c == null) {
  310.             super.setTimestamp(timestamp);
  311.         } else {
  312.             timestamp = timestamp * AV_TIME_BASE / 1000000L;
  313.             /* add the stream start time */
  314.             if (oc.start_time() != AV_NOPTS_VALUE) {
  315.                 timestamp += oc.start_time();
  316.             }
  317.             if ((ret = avformat_seek_file(oc, -1, Long.MIN_VALUE, timestamp, Long.MAX_VALUE, AVSEEK_FLAG_BACKWARD)) < 0) {
  318.                 throw new Exception("avformat_seek_file() error " + ret + ": Could not seek file to timestamp " + timestamp + ".");
  319.             }
  320.             avcodec_flush_buffers(video_c);
  321.             if (audio_c != null) {
  322.                 avcodec_flush_buffers(audio_c);
  323.             }
  324.             while (this.timestamp > timestamp && grab(false) != null) {
  325.                 // flush frames if seeking backwards
  326.             }
  327.             while (this.timestamp < timestamp && grab(false) != null) {
  328.                 // decode up to the desired frame
  329.             }
  330.             frameGrabbed = true;
  331.         }
  332.     }
  333.  
  334.     @Override
  335.     public int getLengthInFrames() {
  336.         // best guess...
  337.         return (int) (getLengthInTime() * getFrameRate() / 1000000L);
  338.     }
  339.  
  340.     @Override
  341.     public long getLengthInTime() {
  342.         return oc.duration() * 1000000L / AV_TIME_BASE;
  343.     }
  344.  
  345.     public void start() throws Exception {
  346.         synchronized (com.googlecode.javacv.cpp.avcodec.class) {
  347.             startUnsafe();
  348.         }
  349.     }
  350.  
  351.     public void startUnsafe() throws Exception {
  352.         int ret;
  353.         img_convert_ctx = null;
  354.         oc = new AVFormatContext(null);
  355.         video_c = null;
  356.         audio_c = null;
  357.         pkt = new AVPacket();
  358.         pkt2 = new AVPacket();
  359.         sizeof_pkt = pkt.sizeof();
  360.         got_frame = new int[1];
  361.         return_image = null;
  362.         frameGrabbed = false;
  363.         frame = new Frame();
  364.         timestamp = 0;
  365.         frameNumber = 0;
  366.  
  367.         pkt2.size(0);
  368.  
  369.         // Open video file
  370.         AVInputFormat f = null;
  371.         if (format != null && format.length() > 0) {
  372.             if ((f = av_find_input_format(format)) == null) {
  373.                 throw new Exception("av_find_input_format() error: Could not find input format \"" + format + "\".");
  374.             }
  375.         }
  376.         AVDictionary options = new AVDictionary(null);
  377.         if (frameRate > 0) {
  378.             AVRational r = av_d2q(frameRate, 1001000);
  379.             av_dict_set(options, "framerate", r.num() + "/" + r.den(), 0);
  380.         }
  381.         if (imageMode != ImageMode.RAW) {
  382.             av_dict_set(options, "pixel_format", imageMode == ImageMode.COLOR ? "bgr24" : "gray8", 0);
  383.         }
  384.         if (imageWidth > 0 && imageHeight > 0) {
  385.             av_dict_set(options, "video_size", imageWidth + "x" + imageHeight, 0);
  386.         }
  387.         if (sampleRate > 0) {
  388.             av_dict_set(options, "sample_rate", "" + sampleRate, 0);
  389.         }
  390.         if (audioChannels > 0) {
  391.             av_dict_set(options, "channels", "" + audioChannels, 0);
  392.         }
  393.         if ((ret = avformat_open_input(oc, filename, f, options)) < 0) {
  394.             throw new Exception("avformat_open_input() error " + ret + ": Could not open input \"" + filename + "\". (Has setFormat() been called?)");
  395.         }
  396.         av_dict_free(options);
  397.  
  398.         // Retrieve stream information
  399.         if ((ret = avformat_find_stream_info(oc, (PointerPointer) null)) < 0) {
  400.             throw new Exception("avformat_find_stream_info() error " + ret + ": Could not find stream information.");
  401.         }
  402.  
  403.         // Dump information about file onto standard error
  404.         av_dump_format(oc, 0, filename, 0);
  405.  
  406.         // Find the first video and audio stream
  407.         video_st = audio_st = null;
  408.         int nb_streams = oc.nb_streams();
  409.         for (int i = 0; i < nb_streams; i++) {
  410.             AVStream st = oc.streams(i);
  411.             // Get a pointer to the codec context for the video or audio stream
  412.             AVCodecContext c = st.codec();
  413.             if (video_st == null && c.codec_type() == AVMEDIA_TYPE_VIDEO) {
  414.                 video_st = st;
  415.                 video_c = c;
  416.             } else if (audio_st == null && c.codec_type() == AVMEDIA_TYPE_AUDIO) {
  417.                 audio_st = st;
  418.                 audio_c = c;
  419.             }
  420.         }
  421.         if (video_st == null && audio_st == null) {
  422.             throw new Exception("Did not find a video or audio stream inside \"" + filename + "\".");
  423.         }
  424.  
  425.         if (video_st != null) {
  426.             // Find the decoder for the video stream
  427.             AVCodec codec = avcodec_find_decoder(video_c.codec_id());
  428.             if (codec == null) {
  429.                 throw new Exception("avcodec_find_decoder() error: Unsupported video format or codec not found: " + video_c.codec_id() + ".");
  430.             }
  431.  
  432.             // Open video codec
  433.             if ((ret = avcodec_open2(video_c, codec, (PointerPointer) null)) < 0) {
  434.                 throw new Exception("avcodec_open2() error " + ret + ": Could not open video codec.");
  435.             }
  436.  
  437.             // Hack to correct wrong frame rates that seem to be generated by some codecs
  438.             if (video_c.time_base().num() > 1000 && video_c.time_base().den() == 1) {
  439.                 video_c.time_base().den(1000);
  440.             }
  441.  
  442.             // Allocate video frame and an AVFrame structure for the RGB image
  443.             if ((picture = avcodec_alloc_frame()) == null) {
  444.                 throw new Exception("avcodec_alloc_frame() error: Could not allocate raw picture frame.");
  445.             }
  446.             if ((picture_rgb = avcodec_alloc_frame()) == null) {
  447.                 throw new Exception("avcodec_alloc_frame() error: Could not allocate RGB picture frame.");
  448.             }
  449.  
  450.             int width = getImageWidth() > 0 ? getImageWidth() : video_c.width();
  451.             int height = getImageHeight() > 0 ? getImageHeight() : video_c.height();
  452.  
  453.             switch (imageMode) {
  454.             case COLOR:
  455.             case GRAY:
  456.                 int fmt = getPixelFormat();
  457.  
  458.                 // Determine required buffer size and allocate buffer
  459.                 int size = avpicture_get_size(fmt, width, height);
  460.                 buffer_rgb = new BytePointer(av_malloc(size));
  461.  
  462.                 // Assign appropriate parts of buffer to image planes in picture_rgb
  463.                 // Note that picture_rgb is an AVFrame, but AVFrame is a superset of AVPicture
  464.                 avpicture_fill(new AVPicture(picture_rgb), buffer_rgb, fmt, width, height);
  465.  
  466.                 return_image = IplImage.createHeader(width, height, IPL_DEPTH_8U, 1);
  467.                 break;
  468.  
  469.             case RAW:
  470.                 buffer_rgb = null;
  471.                 return_image = IplImage.createHeader(video_c.width(), video_c.height(), IPL_DEPTH_8U, 1);
  472.                 break;
  473.  
  474.             default:
  475.                 assert false;
  476.             }
  477.         }
  478.  
  479.         if (audio_st != null) {
  480.             // Find the decoder for the audio stream
  481.             AVCodec codec = avcodec_find_decoder(audio_c.codec_id());
  482.             if (codec == null) {
  483.                 throw new Exception("avcodec_find_decoder() error: Unsupported audio format or codec not found: " + audio_c.codec_id() + ".");
  484.             }
  485.  
  486.             // Open audio codec
  487.             if ((ret = avcodec_open2(audio_c, codec, (PointerPointer) null)) < 0) {
  488.                 throw new Exception("avcodec_open2() error " + ret + ": Could not open audio codec.");
  489.             }
  490.  
  491.             // Allocate audio samples frame
  492.             if ((samples_frame = avcodec_alloc_frame()) == null) {
  493.                 throw new Exception("avcodec_alloc_frame() error: Could not allocate audio frame.");
  494.             }
  495.         }
  496.     }
  497.  
  498.     public void stop() throws Exception {
  499.         release();
  500.     }
  501.  
  502.     public void trigger() throws Exception {
  503.         if (oc == null || oc.isNull()) {
  504.             throw new Exception("Could not trigger: No AVFormatContext. (Has start() been called?)");
  505.         }
  506.         if (pkt2.size() > 0) {
  507.             pkt2.size(0);
  508.             av_free_packet(pkt);
  509.         }
  510.         for (int i = 0; i < numBuffers + 1; i++) {
  511.             if (av_read_frame(oc, pkt) < 0) {
  512.                 return;
  513.             }
  514.             av_free_packet(pkt);
  515.         }
  516.     }
  517.  
  518.     private void processImage() throws Exception {
  519.         switch (imageMode) {
  520.         case COLOR:
  521.         case GRAY:
  522.             // Deinterlace Picture
  523.             if (deinterlace) {
  524.                 AVPicture p = new AVPicture(picture);
  525.                 avpicture_deinterlace(p, p, video_c.pix_fmt(), video_c.width(), video_c.height());
  526.             }
  527.  
  528.             // Convert the image into BGR or GRAY format that OpenCV uses
  529.             img_convert_ctx = sws_getCachedContext(img_convert_ctx, video_c.width(), video_c.height(), video_c.pix_fmt(), getImageWidth(), getImageHeight(), getPixelFormat(), SWS_BILINEAR, null, null, (DoublePointer) null);
  530.             if (img_convert_ctx == null) {
  531.                 throw new Exception("sws_getCachedContext() error: Cannot initialize the conversion context.");
  532.             }
  533.  
  534.             // Convert the image from its native format to RGB or GRAY
  535.             sws_scale(img_convert_ctx, new PointerPointer(picture), picture.linesize(), 0, video_c.height(), new PointerPointer(picture_rgb), picture_rgb.linesize());
  536.             return_image.imageData(buffer_rgb);
  537.             return_image.widthStep(picture_rgb.linesize(0));
  538.             break;
  539.  
  540.         case RAW:
  541.             assert video_c.width() == return_image.width() && video_c.height() == return_image.height();
  542.             return_image.imageData(picture.data(0));
  543.             return_image.widthStep(picture.linesize(0));
  544.             break;
  545.  
  546.         default:
  547.             assert false;
  548.         }
  549.         return_image.imageSize(return_image.height() * return_image.widthStep());
  550.         return_image.nChannels(return_image.widthStep() / return_image.width());
  551.     }
  552.  
  553.     public IplImage grab() throws Exception {
  554.         Frame frame = grabFrame(true, false, false);
  555.         return frame != null ? frame.image : null;
  556.     }
  557.  
  558.     private IplImage grab(boolean processImage) throws Exception {
  559.         Frame frame = grabFrame(processImage, false, false);
  560.         return frame != null ? frame.image : null;
  561.     }
  562.  
  563.     @Override
  564.     public Frame grabFrame() throws Exception {
  565.         return grabFrame(true, true, false);
  566.     }
  567.  
  568.     public Frame grabKeyFrame() throws Exception {
  569.         return grabFrame(true, false, true);
  570.     }
  571.  
  572.     private Frame grabFrame(boolean processImage, boolean doAudio, boolean iframes) throws Exception {
  573.         if (oc == null || oc.isNull()) {
  574.             throw new Exception("Could not grab: No AVFormatContext. (Has start() been called?)");
  575.         }
  576.         frame.keyFrame = false;
  577.         frame.image = null;
  578.         frame.samples = null;
  579.         if (frameGrabbed) {
  580.             frameGrabbed = false;
  581.             if (processImage) {
  582.                 processImage();
  583.             }
  584.             frame.image = return_image;
  585.             return frame;
  586.         }
  587.         boolean done = false;
  588.         while (!done) {
  589.             if (pkt2.size() <= 0) {
  590.                 if (av_read_frame(oc, pkt) < 0) {
  591.                     if (video_st != null) {
  592.                         // The video codec may have buffered some frames
  593.                         pkt.stream_index(video_st.index());
  594.                         pkt.data(null);
  595.                         pkt.size(0);
  596.                     } else {
  597.                         return null;
  598.                     }
  599.                 }
  600.             }
  601.  
  602.             // Is this a packet from the video stream?
  603.             if (video_st != null && pkt.stream_index() == video_st.index() && pkt.flags() == AV_PKT_FLAG_KEY) {
  604.                 // Decode video frame
  605.                 int len = avcodec_decode_video2(video_c, picture, got_frame, pkt);
  606.  
  607.                 // Did we get a video frame?
  608.                 if (len >= 0 && got_frame[0] != 0) {
  609.                     long pts = av_frame_get_best_effort_timestamp(picture);
  610.                     AVRational time_base = video_st.time_base();
  611.                     timestamp = 1000000L * pts * time_base.num() / time_base.den();
  612.                     // best guess, AVCodecContext.frame_number = number of decoded frames...
  613.                     frameNumber = (int) (timestamp * getFrameRate() / 1000000L);
  614.                     if (processImage && picture.pict_type() == AV_PICTURE_TYPE_I) {
  615.                         processImage();
  616.                     }
  617.                     done = true;
  618.                     frame.keyFrame = picture.key_frame() != 0;
  619.                     frame.image = return_image;
  620.                 } else if (pkt.data() == null && pkt.size() == 0) {
  621.                     return null;
  622.                 }
  623.             } else if (doAudio && audio_st != null && pkt.stream_index() == audio_st.index()) {
  624.                 if (pkt2.size() <= 0) {
  625.                     // HashMap is unacceptably slow on Android
  626.                     // pkt2.put(pkt);
  627.                     BytePointer.memcpy(pkt2, pkt, sizeof_pkt);
  628.                 }
  629.                 avcodec_get_frame_defaults(samples_frame);
  630.                 // Decode audio frame
  631.                 int len = avcodec_decode_audio4(audio_c, samples_frame, got_frame, pkt2);
  632.                 if (len <= 0) {
  633.                     // On error, trash the whole packet
  634.                     pkt2.size(0);
  635.                 } else {
  636.                     pkt2.data(pkt2.data().position(len));
  637.                     pkt2.size(pkt2.size() - len);
  638.                     if (got_frame[0] != 0) {
  639.                         long pts = av_frame_get_best_effort_timestamp(samples_frame);
  640.                         AVRational time_base = audio_st.time_base();
  641.                         timestamp = 1000000L * pts * time_base.num() / time_base.den();
  642.                         /* if a frame has been decoded, output it */
  643.                         done = true;
  644.                         int sample_format = samples_frame.format();
  645.                         int planes = av_sample_fmt_is_planar(sample_format) != 0 ? (int) samples_frame.channels() : 1;
  646.                         int data_size = av_samples_get_buffer_size((IntPointer) null, audio_c.channels(), samples_frame.nb_samples(), audio_c.sample_fmt(), 1) / planes;
  647.                         if (samples_buf == null || samples_buf.length != planes) {
  648.                             samples_ptr = new BytePointer[planes];
  649.                             samples_buf = new Buffer[planes];
  650.                         }
  651.                         frame.keyFrame = samples_frame.key_frame() != 0;
  652.                         frame.samples = samples_buf;
  653.                         int sample_size = data_size / av_get_bytes_per_sample(sample_format);
  654.                         for (int i = 0; i < planes; i++) {
  655.                             BytePointer p = samples_frame.data(i);
  656.                             if (!p.equals(samples_ptr[i]) || samples_ptr[i].capacity() < data_size) {
  657.                                 samples_ptr[i] = p.capacity(data_size);
  658.                                 ByteBuffer b = p.asBuffer();
  659.                                 switch (sample_format) {
  660.                                 case AV_SAMPLE_FMT_U8:
  661.                                 case AV_SAMPLE_FMT_U8P:
  662.                                     samples_buf[i] = b;
  663.                                     break;
  664.                                 case AV_SAMPLE_FMT_S16:
  665.                                 case AV_SAMPLE_FMT_S16P:
  666.                                     samples_buf[i] = b.asShortBuffer();
  667.                                     break;
  668.                                 case AV_SAMPLE_FMT_S32:
  669.                                 case AV_SAMPLE_FMT_S32P:
  670.                                     samples_buf[i] = b.asIntBuffer();
  671.                                     break;
  672.                                 case AV_SAMPLE_FMT_FLT:
  673.                                 case AV_SAMPLE_FMT_FLTP:
  674.                                     samples_buf[i] = b.asFloatBuffer();
  675.                                     break;
  676.                                 case AV_SAMPLE_FMT_DBL:
  677.                                 case AV_SAMPLE_FMT_DBLP:
  678.                                     samples_buf[i] = b.asDoubleBuffer();
  679.                                     break;
  680.                                 default:
  681.                                     assert false;
  682.                                 }
  683.                             }
  684.                             samples_buf[i].position(0).limit(sample_size);
  685.                         }
  686.                     }
  687.                 }
  688.             }
  689.  
  690.             if (pkt2.size() <= 0) {
  691.                 // Free the packet that was allocated by av_read_frame
  692.                 av_free_packet(pkt);
  693.             }
  694.         }
  695.         return frame;
  696.     }
  697. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement