2013-02-11 9 views
13

के रूप में कैमरे को स्ट्रीम करना SO और google खोजने के कई दिनों बाद मैं हारना शुरू कर रहा हूं, इसलिए मैंने सोचा कि मैं यहां भी पोस्ट कर सकता हूं।एंड्रॉइड: mjpeg

मैं एक एंड्रॉइड ऐप बना रहा हूं जिसे किसी प्रकार की वीडियो चैट की पेशकश करनी चाहिए। चूंकि यह रीयलटाइम के जितना संभव हो उतना करीब होना चाहिए, मैंने विभिन्न प्रोटोकॉल के बारे में पढ़ा और स्टार्टर्स के लिए एमजेपीईजी (अब ऑडियो के साथ संबंधित नहीं) का प्रयास करने का फैसला किया।

अभी डेटा स्ट्रीमिंग मुझे पागल कर रहा है। कनेक्शन स्थापित हो जाता है, ऐप स्ट्रीम में कैमरे के पूर्वावलोकन फ्रेम लिखना शुरू करता है, लेकिन न तो वीएलसी और न ही मप्लेयर वीडियो खेलना शुरू कर देता है। कनेक्शन की निगरानी से पता चलता है कि डेटा आ रहा है।

इस कोड को एक async कार्य द्वारा निष्पादित किया जाता है कनेक्ट कर रहा है, एक श्रोता सफलता पर सूचित किया जाता है:

try 
    { 
     ServerSocket server = new ServerSocket(8080); 

     socket = server.accept(); 

     server.close(); 

     Log.i(TAG, "New connection to :" + socket.getInetAddress()); 

     stream = new DataOutputStream(socket.getOutputStream()); 
     prepared = true; 
    } 
    catch (IOException e) 
    { 
     Log.e(TAG, e.getMessage(); 
    } 

मेरे पीसी पर मैं अमल 'MPlayer http://tabletIP:8080' और टैबलेट एक कनेक्शन पंजीकृत करता है (और इस तरह शुरू होता है मेरा स्ट्रीमर और कैमरा पूर्वावलोकन)। यह वीएलसी के साथ भी काम करता है।

स्ट्रीमिंग इस धारा के हैडर लिखते हैं:

if (stream != null) 
{ 
    try 
    { 
     // send the header 
     stream.write(("HTTP/1.0 200 OK\r\n" + 
         "Server: iRecon\r\n" + 
         "Connection: close\r\n" + 
         "Max-Age: 0\r\n" + 
         "Expires: 0\r\n" + 
         "Cache-Control: no-cache, private\r\n" + 
         "Pragma: no-cache\r\n" + 
         "Content-Type: multipart/x-mixed-replace; " + 
         "boundary=--" + boundary + 
         "\r\n\r\n").getBytes()); 

     stream.flush(); 

     streaming = true; 
    } 
    catch (IOException e) 
    { 
     notifyOnEncoderError(this, "Error while writing header: " + e.getMessage()); 
     stop(); 
    } 
} 

बाद स्ट्रीमिंग Camera.onPreviewFrame() कॉलबैक के माध्यम से शुरू हो रहा है:

@Override 
public void onPreviewFrame(byte[] data, Camera camera) 
{ 
    frame = data; 

    if (streaming) 
     mHandler.post(this); 
} 

@Override 
public void run() 
{ 
    // TODO: cache not filling? 
    try 
    { 
        // buffer is a ByteArrayOutputStream 
     buffer.reset(); 

     switch (imageFormat) 
     { 
      case ImageFormat.JPEG: 
       // nothing to do, leave it that way 
       buffer.write(frame); 
       break; 

      case ImageFormat.NV16: 
      case ImageFormat.NV21: 
      case ImageFormat.YUY2: 
      case ImageFormat.YV12: 
       new YuvImage(frame, imageFormat, w, h, null).compressToJpeg(area, 100, buffer); 
       break; 

      default: 
       throw new IOException("Error while encoding: unsupported image format"); 
     } 

     buffer.flush(); 

     // write the content header 
     stream.write(("--" + boundary + "\r\n" + 
         "Content-type: image/jpg\r\n" + 
         "Content-Length: " + buffer.size() + 
         "\r\n\r\n").getBytes()); 

     // Should omit the array copy 
     buffer.writeTo(stream); 

     stream.write("\r\n\r\n".getBytes()); 
     stream.flush(); 
    } 
    catch (IOException e) 
    { 
     stop(); 
     notifyOnEncoderError(this, e.getMessage()); 
    } 
} 

कोई अपवाद नहीं फेंक दिया है। एमएचंडलर अपने ही हैंडलर थ्रेड में चलता है। बस यह सुनिश्चित करने के लिए कि मैंने एक AsyncTask का उपयोग करने की कोशिश की, कोई फायदा नहीं हुआ (बीटीडब्ल्यू, क्या यह बेहतर है?)।

एन्कोडेड फ्रेम एंड्रॉइड पक्ष पर ठीक हैं, मैंने उन्हें jpg फ़ाइलों में सहेजा और उन्हें खोल सकता है।

मेरा अनुमान है कि मुझे किसी भी तरह से डेटा क्लस्टर करना होगा या सॉकेट या कुछ के लिए कुछ विकल्प सेट करना होगा, लेकिन .... अच्छा, मैं अटक गया हूं।

tl; डॉ: वीएलसी धारा नहीं खेल, MPlayer कहते हैं, 'भरने नहीं कैश', शायद आखिरी कोड खंड में समस्या, मदद की ज़रूरत है ~ :)

तुम कृपया धन्यवाद!

उत्तर

11

मुझे यह मिला। लगता है, जैसे मेरे http-/content-headers गड़बड़ हो गए थे। उचित हेडर होना चाहिए:

stream.write(("HTTP/1.0 200 OK\r\n" + 
          "Server: iRecon\r\n" + 
          "Connection: close\r\n" + 
          "Max-Age: 0\r\n" + 
          "Expires: 0\r\n" + 
          "Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n" + 
          "Pragma: no-cache\r\n" + 
          "Content-Type: multipart/x-mixed-replace; " + 
          "boundary=" + boundary + "\r\n" + 
          "\r\n" + 
          "--" + boundary + "\r\n").getBytes()); 

और

stream.write(("Content-type: image/jpeg\r\n" + 
         "Content-Length: " + buffer.size() + "\r\n" + 
         "X-Timestamp:" + timestamp + "\r\n" + 
         "\r\n").getBytes()); 

buffer.writeTo(stream); 
stream.write(("\r\n--" + boundary + "\r\n").getBytes()); 
बेशक

, जहां सीमा डाल करने के लिए अपनी खुद की पसंद है। इसके अलावा शायद कुछ फ़ील्ड हैं जो वैकल्पिक हैं (उदाहरण के लिए कैश-कंट्रोल में सबसे अधिक), लेकिन यह काम करता है और अब तक मैं उन्हें छीनने के लिए बहुत आलसी था। महत्वपूर्ण हिस्सा लाइनब्रैक को याद रखना है (\r\n चीजें) ...

+1

क्या आप कैमरा से एमजेपीईजी प्राप्त करने के लिए कोड पोस्ट कर सकते हैं। – Sourav301

+0

@ सौरव आपकी कक्षा को कैमरा लागू करना है। पूर्वावलोकनवॉलबैक। अपने कैमरे के कॉल कैमरे को शुरू करने के बाद .setPreviewCallback (...)। जेपीईजीएस को पुनः प्राप्त करने के लिए बाकी मेरे प्रश्न में पहले से ही है। – Managarm

+1

उन लोगों के लिए जो सीमा तय करनी चाहिए, यह कोई जावा स्ट्रिंग हो सकती है (वर्णमाला शामिल है, सुनिश्चित नहीं है कि संख्याएं और विशेष वर्ण काम करेंगे)। –