2011-05-31 18 views
9

मैं एक सप्ताह के बाद से xuggle साथ काम कर रहा हूँ और मैं एक विधि लिखा एक वीडियो से एक फ्रेम पाने के लिए, लेकिन अगर वीडियो लंबा है इस विधि बहुत अधिक समय लेता है पाने के लिए सबसे अच्छा तरीका:जावा - Xuggle - एक फ्रेम

public static void getFrameBySec(IContainer container, int videoStreamId, IStreamCoder videoCoder, IVideoResampler resampler, double sec) 
{ 
    BufferedImage javaImage = new BufferedImage(videoCoder.getWidth(), videoCoder.getHeight(), BufferedImage.TYPE_3BYTE_BGR); 
    IConverter converter = ConverterFactory.createConverter(javaImage, IPixelFormat.Type.BGR24); 
    IPacket packet = IPacket.make(); 
    while(container.readNextPacket(packet) >= 0) 
    { 
     if (packet.getStreamIndex() == videoStreamId) 
     { 
      IVideoPicture picture = IVideoPicture.make(videoCoder.getPixelType(), videoCoder.getWidth(), videoCoder.getHeight()); 
      int offset = 0; 
      while(offset < packet.getSize()) 
      { 
       int bytesDecoded = videoCoder.decodeVideo(picture, packet, offset); 
       if (bytesDecoded < 0) 
        throw new RuntimeException("got error decoding video"); 
       offset += bytesDecoded; 
       if (picture.isComplete()) 
       { 
        IVideoPicture newPic = picture; 
        if (resampler != null) 
        { 
         newPic = IVideoPicture.make(resampler.getOutputPixelFormat(), picture.getWidth(), picture.getHeight()); 

         if (resampler.resample(newPic, picture) < 0) 
          throw new RuntimeException("could not resample video from"); 
        } 
        if (newPic.getPixelType() != IPixelFormat.Type.BGR24) 
          throw new RuntimeException("could not decode video as RGB 32 bit data in"); 

        javaImage = converter.toImage(newPic); 
        try 
        { 
         double seconds = ((double)picture.getPts())/Global.DEFAULT_PTS_PER_SECOND; 
         if (seconds >= sec && seconds <= (sec +(Global.DEFAULT_PTS_PER_SECOND))) 
         { 

          File file = new File(Config.MULTIMEDIA_PATH, "frame_" + sec + ".png"); 
          ImageIO.write(javaImage, "png", file); 
          System.out.printf("at elapsed time of %6.3f seconds wrote: %s \n", seconds, file); 
          return; 
         } 
        } 
        catch (Exception e) 
        { 
         e.printStackTrace(); 
        } 
       } 
      } 
     } 
     else 
     { 
      // This packet isn't part of our video stream, so we just 
      // silently drop it. 
     } 
    } 
    converter.delete(); 
} 

क्या आप इसे करने का बेहतर तरीका जानते हैं?

उत्तर

2

बस अपना कोड पढ़ने से मुझे कुछ अनुकूलन दिखाई दे सकते हैं।

एक बार आप पहली बार पूरी फ़ाइल के माध्यम से पढ़ते हैं, बाइटऑफसेट और सेकंड का सूचकांक बनाते हैं। फिर फ़ंक्शन दिए गए सेकंड से बाइटऑफसेट की तलाश कर सकता है और आप उस ऑफ़सेट पर वीडियो को डीकोड कर सकते हैं और अपना शेष कोड कर सकते हैं।

एक और विकल्प आपकी विधि का उपयोग करना है, हर बार पूरी फाइल के माध्यम से पढ़ना, लेकिन सभी resampler, newPic, और जावा छवि कनवर्टर कोड को कॉल करने के बजाय, जांचें कि सेकंड पहले मैच में हैं या नहीं। यदि वे करते हैं, तो छवि को प्रदर्शित करने के लिए एक नई तस्वीर में परिवर्तित करें।

तो

if(picture.isComplete()){ 

try { 

    double seconds = ((double)picture.getPts())/Global.DEFAULT_PTS_PER_SECOND; 
    if (seconds >= sec && seconds <= (sec +(Global.DEFAULT_PTS_PER_SECOND))) 
    { 
    Resample image 
    Convert Image 
    Do File stuff 
    } 
2

उपयोग seekKeyFrame विकल्प। आप वीडियो फ़ंक्शन में किसी भी समय ढूंढने के लिए इस फ़ंक्शन का उपयोग कर सकते हैं (समय मिलीसेकंड में है)।

double timeBase = 0; 
int videoStreamId = -1; 

private void seekToMs(IContainer container, long timeMs) { 
    if(videoStreamId == -1) { 
     for(int i = 0; i < container.getNumStreams(); i++) { 
      IStream stream = container.getStream(i); 
      IStreamCoder coder = stream.getStreamCoder(); 
      if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) { 
       videoStreamId = i; 
       timeBase = stream.getTimeBase().getDouble(); 
       break; 
      } 
     } 
    } 

    long seekTo = (long) (timeMs/1000.0/timeBase); 
    container.seekKeyFrame(videoStreamId, seekTo, IContainer.SEEK_FLAG_BACKWARDS); 
} 

वहां से आप छवियों को छवियों को प्राप्त करने के अपने क्लासिक while(container.readNextPacket(packet) >= 0) विधि का उपयोग करते हैं।

नोटिस: यह सही समय की तलाश नहीं करेगा लेकिन अनुमानित है कि आपको अभी भी पैकेट (लेकिन निश्चित रूप से पहले से कम) के माध्यम से जाना होगा।

+0

इस मामले में "टाइमएम" या "तलाश टीओ" क्या है? मुझे काफी कुछ नहीं मिला .. मैं वर्तमान पॉट्स के सापेक्ष कैसे कूदूं? [IVideoPicture.getPts()] – KarlP

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^