اذهب إلى المحتوى

السؤال

نشر
    public void convert() throws IOException {
        String videoPath = "/sdcard/input.mp4";

        // Get the video resolution
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        int videoResolution = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));

        // If the video resolution is higher than 360p, downscale it to 360p
        if (videoResolution > 360) {
            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
            retriever.setDataSource(videoPath);
            Bitmap bmp = retriever.getFrameAtTime();
            int newWidth = 360;
            int newHeight = (int) (bmp.getHeight() * newWidth / bmp.getWidth());
            Bitmap resizedBmp = Bitmap.createScaledBitmap(bmp, newWidth, newHeight, true);
            retriever.release();

            // Save the video to the phone
            MediaMuxer muxer = null;
            try {
                muxer = new MediaMuxer(videoPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

                // Add the video track
                int videoTrackIndex = muxer.addTrack(MediaFormat.createVideoFormat(videoPath, newWidth, newHeight));

                // Add the audio track
                int audioTrackIndex = muxer.addTrack(MediaFormat.createAudioFormat(videoPath, 44100, 2));

                // Start writing to the muxer
                muxer.start();

                // Write the video frames to the muxer
                ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024);
                for (int i = 0; i < resizedBmp.getHeight(); i++) {
                    buffer.clear();
                    resizedBmp.getPixels(buffer.array(), 0, resizedBmp.getWidth(), 0, i, resizedBmp.getWidth(), resizedBmp.getHeight());
                    byte[] bytes = ByteBuffer.wrap(buffer.array()).asByteArray();
                    muxer.writeSampleData(videoTrackIndex, bytes, bytes.length);
                }

                // Write the audio samples to the muxer
                for (int i = 0; i < resizedBmp.getHeight(); i++) {
                    buffer.clear();
                    resizedBmp.getPixels(buffer.array(), 0, resizedBmp.getWidth(), 0, i, resizedBmp.getWidth(), resizedBmp.getHeight());
                    byte[] bytes = ByteBuffer.wrap(buffer.array()).asByteArray();
                    muxer.writeSampleData(audioTrackIndex, bytes, bytes.length);
                }

                // Stop writing to the muxer
                muxer.stop();
                muxer.release();
            } catch (IOException e) {
                Log.e("MainActivity", "Error writing to muxer", e);
            }
        }

// Set the video view's media controller
        vedgetr.setMediaController(new MediaController(this));

// Set the video view's video path
        vedgetr.setVideoPath(videoPath);

// Start playing the video
        vedgetr.start();
    }

 

Recommended Posts

  • 0
نشر

في البداية، الكود يقوم بإنشاء مثيل من MediaMetadataRetriever للحصول على الدقة (العرض) للفيديو. ولكنه لا يقوم بتحرير مصدر البيانات (data source) في المثيل الأول، بينما يقوم بذلك في المثيل الثاني. وذلك ليس منطقيًا وقد يؤدي إلى خطأ في تشغيل الفيديو.

حاول إصلاح الجزء الأول من الكود ليصبح كالتالي:

public void convert() throws IOException {
    String videoPath = "/sdcard/input.mp4";

    // Get the video resolution
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    retriever.setDataSource(videoPath); // قم بتحديد مصدر البيانات للمثيل
    int videoResolution = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
    retriever.release(); // قم بإطلاق المثيل بعد الانتهاء من الاستخدام

    // بقية الكود كما هو...
}

والجزء الذي يعيد حجم الصورة المصغرة (thumbnail) للفيديو ليس دقيقًا، ففي حالة إعادة تحجيم الصورة، من الأفضل استخدام طرق معينة للحفاظ على نسبة الأبعاد الصحيحة، وهناك أيضًا بعض الأخطاء في تسجيل الفيديو والصوت في الملتقط (muxer).

ولحل تلك المشكلة وتحسين عملية تسجيل الفيديو والصوت، من الأفضل  استخدام مكتبة مثل FFmpeg لتنفيذ تلك الوظائف بطريقة أكثر دقة وفاعلية، وتستطيع تضمين مكتبة FFmpeg في تطبيق Android الخاص بك واستخدامها لإجراء تحويلات وإعادة تحجيم الفيديو وتسجيله بأكثر دقة.

ولاحظ أن استخدام FFmpeg يتطلب بعض الوقت والمجهود للتعامل مع الـ API الخاص بها، وفي حال كنت ترغب في الاستمرار باستخدام الأسلوب الحالي، فمن الأفضل التحقق من مثال كامل لتحويل وتغيير حجم الفيديو باستخدام MediaCodec وMediaMuxer وSurface وغيرها من الأدوات المتوفرة في Android SDK.

وعامًة للحفاظ على نسبة الأبعاد الصحيحة عند إعادة تحجيم الصورة المصغرة، استخدم دالة Bitmap.createScaledBitmap() بطريقة تحسب الارتفاع الجديد بناءًا على النسبة بين العرض الجديد والعرض الأصلي:

// Calculate the new dimensions while maintaining the aspect ratio
int newWidth = 360;
int newHeight = (int) (videoResolution * 1.0 / bmp.getWidth() * newWidth);

// Resize the bitmap
Bitmap resizedBmp = Bitmap.createScaledBitmap(bmp, newWidth, newHeight, true);

ولتسجيل الفيديو والصوت بشكل صحيح، استخدم MediaCodec لتشفير الإطارات الفعلية من الفيديو والصوت ومن ثم تسجيلها باستخدام MediaMuxer.

وتحتاج إلى استخدام MediaCodec للحصول على الإطارات (frames) من الفيديو وترميزها إلى تنسيق مثل H.264، ثم استخدام MediaMuxer لدمج البيانات المشفرة مع تنسيق صوتي مناسب (مثل AAC) لإنشاء ملف فيديو نهائي.

وكما ذكرت هناك مكتبات جاهزة تساعدك في تحويل وتعديل الفيديو بشكل أسهل، مثل FFmpeg وغيرها.

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...