美文网首页
NuMediaExtractor 使用随笔

NuMediaExtractor 使用随笔

作者: Nothing_655f | 来源:发表于2022-03-25 17:20 被阅读0次

    NuMediaExtractor 使用随笔

    记录一个随笔改动,有个改法是想获取片源中某个特定的信息,然后根据其来判断选择player,在MediaPlayerFactory@scoreFactory 中就可以直接调用extractor中来获取extractor中一些mime信息

        virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                int fd,
                                int64_t offset,
                                int64_t length,
                                float /*curScore*/) {
                // ...
                sp<NuMediaExtractor> extractor = new NuMediaExtractor;
                extractor->setDataSource(fd, 0, 0x7ffffffffffffffL);
                size_t nums = extractor->countTracks();
                sp<AMessage> format;
                AString mime;
                for (size_t i=0; i<nums; i++) {
                    if (extractor->getTrackFormat(i, &format) == OK
                        && format->findString("mime", &mime)) {
                        if (!strncasecmp(mime.c_str(), "text/pgs", 8)) {
                            return 1.2;
                        }
                    }
                }
                // ...
        }
    

    然后看了下这个用法其实在NDK中就有了,具体看 frameworks/av/media/ndk/NdkMediaExtractor.cpp
    在Android P中的frameworks/base/media/jni/soundpool/SoundPool.cpp代码也可以看到其用法

    static status_t decode(int fd, int64_t offset, int64_t length,
            uint32_t *rate, int *numChannels, audio_format_t *audioFormat,
            sp<MemoryHeapBase> heap, size_t *memsize) {
    
        ALOGV("fd %d, offset %" PRId64 ", size %" PRId64, fd, offset, length);
        AMediaExtractor *ex = AMediaExtractor_new();
        status_t err = AMediaExtractor_setDataSourceFd(ex, fd, offset, length);
    
        if (err != AMEDIA_OK) {
            AMediaExtractor_delete(ex);
            return err;
        }
    
        *audioFormat = AUDIO_FORMAT_PCM_16_BIT;
    
        size_t numTracks = AMediaExtractor_getTrackCount(ex);
        for (size_t i = 0; i < numTracks; i++) {
            AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
            const char *mime;
            if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
                AMediaExtractor_delete(ex);
                AMediaFormat_delete(format);
                return UNKNOWN_ERROR;
            }
            if (strncmp(mime, "audio/", 6) == 0) {
    
                AMediaCodec *codec = AMediaCodec_createDecoderByType(mime);
                if (codec == NULL
                        || AMediaCodec_configure(codec, format,
                                NULL /* window */, NULL /* drm */, 0 /* flags */) != AMEDIA_OK
                        || AMediaCodec_start(codec) != AMEDIA_OK
                        || AMediaExtractor_selectTrack(ex, i) != AMEDIA_OK) {
                    AMediaExtractor_delete(ex);
                    AMediaCodec_delete(codec);
                    AMediaFormat_delete(format);
                    return UNKNOWN_ERROR;
                }
    
                bool sawInputEOS = false;
                bool sawOutputEOS = false;
                uint8_t* writePos = static_cast<uint8_t*>(heap->getBase());
                size_t available = heap->getSize();
                size_t written = 0;
    
                AMediaFormat_delete(format);
                format = AMediaCodec_getOutputFormat(codec);
    
                while (!sawOutputEOS) {
                    if (!sawInputEOS) {
                        ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
                        ALOGV("input buffer %zd", bufidx);
                        if (bufidx >= 0) {
                            size_t bufsize;
                            uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
                            if (buf == nullptr) {
                                ALOGE("AMediaCodec_getInputBuffer returned nullptr, short decode");
                                break;
                            }
                            int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
                            ALOGV("read %d", sampleSize);
                            if (sampleSize < 0) {
                                sampleSize = 0;
                                sawInputEOS = true;
                                ALOGV("EOS");
                            }
                            int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    
                            media_status_t mstatus = AMediaCodec_queueInputBuffer(codec, bufidx,
                                    0 /* offset */, sampleSize, presentationTimeUs,
                                    sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
                            if (mstatus != AMEDIA_OK) {
                                // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
                                ALOGE("AMediaCodec_queueInputBuffer returned status %d, short decode",
                                        (int)mstatus);
                                break;
                            }
                            (void)AMediaExtractor_advance(ex);
                        }
                    }
    
                    AMediaCodecBufferInfo info;
                    int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1);
                    ALOGV("dequeueoutput returned: %d", status);
                    if (status >= 0) {
                        if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
                            ALOGV("output EOS");
                            sawOutputEOS = true;
                        }
                        ALOGV("got decoded buffer size %d", info.size);
    
                        uint8_t *buf = AMediaCodec_getOutputBuffer(codec, status, NULL /* out_size */);
                        if (buf == nullptr) {
                            ALOGE("AMediaCodec_getOutputBuffer returned nullptr, short decode");
                            break;
                        }
                        size_t dataSize = info.size;
                        if (dataSize > available) {
                            dataSize = available;
                        }
                        memcpy(writePos, buf + info.offset, dataSize);
                        writePos += dataSize;
                        written += dataSize;
                        available -= dataSize;
                        media_status_t mstatus = AMediaCodec_releaseOutputBuffer(
                                codec, status, false /* render */);
                        if (mstatus != AMEDIA_OK) {
                            // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
                            ALOGE("AMediaCodec_releaseOutputBuffer returned status %d, short decode",
                                    (int)mstatus);
                            break;
                        }
                        if (available == 0) {
                            // there might be more data, but there's no space for it
                            sawOutputEOS = true;
                        }
                    } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
                        ALOGV("output buffers changed");
                    } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
                        AMediaFormat_delete(format);
                        format = AMediaCodec_getOutputFormat(codec);
                        ALOGV("format changed to: %s", AMediaFormat_toString(format));
                    } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
                        ALOGV("no output buffer right now");
                    } else if (status <= AMEDIA_ERROR_BASE) {
                        ALOGE("decode error: %d", status);
                        break;
                    } else {
                        ALOGV("unexpected info code: %d", status);
                    }
                }
    
                (void)AMediaCodec_stop(codec);
                (void)AMediaCodec_delete(codec);
                (void)AMediaExtractor_delete(ex);
                if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, (int32_t*) rate) ||
                        !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, numChannels)) {
                    (void)AMediaFormat_delete(format);
                    return UNKNOWN_ERROR;
                }
                (void)AMediaFormat_delete(format);
                *memsize = written;
                return OK;
            }
            (void)AMediaFormat_delete(format);
        }
        (void)AMediaExtractor_delete(ex);
        return UNKNOWN_ERROR;
    }
    
    

    还有一个是往上对接framework MediaExtractor 接口的使用,具体可以看这篇文章分析

    MediaExtractor源码分析 - 简书

    相关文章

      网友评论

          本文标题:NuMediaExtractor 使用随笔

          本文链接:https://www.haomeiwen.com/subject/xfsdjrtx.html