android मीडियाकोडेक और कैमरा: रंगस्थान मेल नहीं खाते हैं




colors h.264 (4)

मैं नए कम-स्तर MediaCodec का उपयोग कर एंड्रॉइड टैबलेट पर कैमरे द्वारा कैप्चर किए गए इनपुट के साथ काम करने के लिए H264 एन्कोडिंग प्राप्त करने का प्रयास कर रहा हूं। मैं इसके साथ कुछ कठिनाइयों से गुजर चुका हूं, क्योंकि MediaCodecAPI खराब दस्तावेज है, लेकिन मुझे आखिर में काम करने के लिए कुछ मिल गया है।

मैं कैमरे को निम्नानुसार स्थापित कर रहा हूं:

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewFormat(ImageFormat.YV12); // <1>
        parameters.setPreviewFpsRange(4000,60000);
        parameters.setPreviewSize(640, 480);            
        mCamera.setParameters(parameters);

एन्कोडिंग भाग के लिए, मैं MediaCodec ऑब्जेक्ट को निम्नानुसार तत्काल कर रहा हूं:

    mediaCodec = MediaCodec.createEncoderByType("video/avc");
    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 640, 480);
    mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 500000);
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
    mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar); // <2>
    mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
    mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    mediaCodec.start();

अंतिम लक्ष्य एक आरटीपी-स्ट्रीम (और स्काइप के साथ मेल खाता है) बनाना है, लेकिन अब तक मैं केवल अपने डेस्कटॉप पर कच्चे H264 को स्ट्रीम कर रहा हूं। परिणाम देखने के लिए मैं निम्नलिखित जीस्ट्रीमर-पाइपलाइन का उपयोग करता हूं:

gst-launch udpsrc port=5555 ! video/x-h264,width=640,height=480,framerate=15/1 ! ffdec_h264 ! autovideosink

सभी रंगों को छोड़कर, अच्छी तरह से काम करता है। मुझे कंप्यूटर में 2 रंगफॉर्म सेट करने की आवश्यकता है: कैमरा-पूर्वावलोकन ( <1> साथ टैग की गई रेखा) और मीडियाकोडेक-ऑब्जेक्ट के लिए एक ( <2> साथ टैग किया गया)

लाइनों के लिए स्वीकार्य मान निर्धारित करने के लिए <1> मैंने parameters.getSupportedPreviewFormats() उपयोग किया parameters.getSupportedPreviewFormats() । इससे, मुझे पता है कि कैमरे पर एकमात्र समर्थित प्रारूप ImageFormat.NV21 और ImageFormat.YV2

<2> , मैंने MediaCodecInfo.CodecCapabilities टाइप वीडियो / एवीसी के लिए प्रोजेक्ट को पुनर्प्राप्त किया, पूर्णांक मान 1 9 ( MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar और 2130708361 के साथ संबंधित है (जो MediaCodecInfo.CodecCapabilities किसी भी मान के अनुरूप नहीं है)।

दुर्घटना में उपरोक्त परिणामों की तुलना में कोई अन्य मूल्य।

इन सेटिंग्स का संयोजन अलग-अलग परिणाम देता है, जो मैं नीचे दिखाऊंगा। एंड्रॉइड पर स्क्रीनशॉट यहां है (यानी "वास्तविक" रंग): Gstreamer द्वारा दिखाए गए परिणाम यहां दिए गए हैं:

<1> = एनवी 21, <2> = COLOR_FormatYUV420Planar

<1> = एनवी 21, <2> = 2130708361

<1> = वाईवी <2> , <2> = COLOR_FormatYUV420Planar

<1> = वाईवी <2> , <2> = 2130708361

जैसा देखा जा सकता है, इनमें से कोई भी संतोषजनक नहीं है। वाईवी 2-रंगस्थान सबसे आशाजनक दिखता है, लेकिन ऐसा लगता है जैसे लाल (सीआर) और नीला (सीबी) उलटा हुआ है। एनवी 21 मुझे लगता है कि अंतःस्थापित लगता है (हालांकि, मैं इस क्षेत्र में कोई विशेषज्ञ नहीं हूं)।

चूंकि उद्देश्य स्काइप के साथ संवाद करना है, मुझे लगता है कि मुझे डिकोडर (यानी जीस्ट्रीमर-कमांड) नहीं बदलना चाहिए, है ना? क्या इसे एंड्रॉइड में हल किया जाना चाहिए और यदि ऐसा है तो कैसे? या इसे कुछ आरटीपी पेलोड जानकारी जोड़कर हल किया जा सकता है? कोई अन्य सुझाव?


कैमरे पर ImageFormat.NV21 सेट और एन्कोडर के लिए COLOR_FormatYUV420Planar के साथ, मेरे मामले में समान नीली छाया को ओवरलैप करने के लिए देखा जाता है। जैसा कि मैं समझता हूं कि उपर्युक्त स्वैप फ़ंक्शन का उपयोग मेरे मामले में नहीं किया जा सकता है, इसके लिए एल्गोरिदम पर कोई सुझाव उपयोग किया जा सकता है? ps: जब कैमरा पूर्वावलोकन प्रारूप YV12 के रूप में सेट किया गया है तो यह डीकोडर पर एक पूर्ण ब्लैक स्क्रीन है


ऐसा लगता है कि एंड्रॉइड वाईवी 12 में ट्रांसमिट कर रहा है, लेकिन एच 264 हेडर में सेट प्रारूप वाईयूवी 420 है। ये प्रारूप बराबर हैं यू और वी चैनल अलग-अलग क्रम में हैं, जो लाल और नीले रंग के स्वैपिंग को बताते हैं।

Android पक्ष की सेटिंग को ठीक करने के लिए सबसे अच्छा होगा। लेकिन अगर कैमरा और एन्कोडर के लिए संगत सेटिंग्स सेट करने का कोई तरीका नहीं है, तो आपको GStreamer पक्ष पर प्रारूप को मजबूर करना होगा।

यह capssetter बाद capssetter तत्व जोड़कर किया जा सकता है

... ! ffdec_h264 ! capssetter caps="video/x-raw-yuv, format=(fourcc)YV12" ! colorspace ! ...


मैंने इसे सरल कार्य का उपयोग करके एंड्रॉइड स्तर पर बाइटप्लेन्स को स्वैप करके हल किया:

public byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
    byte[] i420bytes = new byte[yv12bytes.length];
    for (int i = 0; i < width*height; i++)
        i420bytes[i] = yv12bytes[i];
    for (int i = width*height; i < width*height + (width/2*height/2); i++)
        i420bytes[i] = yv12bytes[i + (width/2*height/2)];
    for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)
        i420bytes[i] = yv12bytes[i - (width/2*height/2)];
    return i420bytes;
}

मुझे लगता है कि मूल्यों को स्वैप करने के लिए यह अधिक कुशल है।

        int wh4 = input.length/6; //wh4 = width*height/4
        byte tmp;
        for (int i=wh4*4; i<wh4*5; i++)
            {
            tmp = input[i];
            input[i] = input[i+wh4];
            input[i+wh4] = tmp;
            }

शायद इससे भी बेहतर, आप बदले में बदल सकते हैं

            inputBuffer.put(input);

सही क्रम में 3 प्लानर स्लाइस के साथ

            inputBuffer.put(input, 0, wh4*4);
            inputBuffer.put(input, wh4*5, wh4);
            inputBuffer.put(input, wh4*4, wh4);

मुझे लगता है कि केवल एक छोटे से ऊपर की ओर होना चाहिए