문제

MediaExtractor를 사용하여 Android에서 MP4를 편집하여 오디오 및 비디오 트랙을 가져와 MediaMowSer를 사용하여 새 파일을 만듭니다.그것은 잘 작동합니다.전화 (및 다른 플레이어)에서 새로운 MP4를 재생할 수 있지만 웹에서 파일을 스트리밍 할 수 없습니다.MediaMuxer를 중지 할 때 로그 메시지가 생성됩니다

"MP4 파일은 유제되지 않습니다."

기본적인 기본 코드 (MPEG4Writer.cpp)를 보았고 작성자가 필요한 Moov 상자 크기를 계산하는 데 어려움을 겪고있는 것처럼 보입니다.비트 전송률이 작가의 매개 변수로 제공되지 않으면 일부 휴리스틱을 사용하여 추측하려고합니다.문제는 MediaMuxer가 MPEG4Writer의 매개 변수를 설정하는 기능을 제공하는 기능을 제공하지 않습니다.나는 뭔가를 놓치거나 파일 (또는 헤더)을 생성하는 다른 수단을 찾고 있다는 것을 멈추고 있습니까?고마워.

도움이 되었습니까?

해결책

mpeg4writer.cpp :

// The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
// where 1MB is the common file size limit for MMS application.
// The default MAX _MOOV_BOX_SIZE value is based on about 3
// minute video recording with a bit rate about 3 Mbps, because
// statistics also show that most of the video captured are going
// to be less than 3 minutes.
.

이것은 MediaMuxer가 어떻게 사용될 수 있는지에 대한 나쁜 가정입니다.우리는 더 높은 res 비디오와 min_moov_box_size가 너무 작습니다.따라서 파일을 유제 할 수 있도록 파일을 다시 작성하여 MDAT 앞에 Moov 헤더를 이동하고 일부 오프셋을 패치하십시오.여기 내 코드가 있습니다.훌륭하지 않습니다.오류 경로는 올바르게 처리되지 않으며 상자의 순서에 대한 가정을합니다.

public void fastPlay(String srcFile, String dstFile)  {
    RandomAccessFile inFile = null;
    FileOutputStream outFile = null;
    try {
        inFile = new RandomAccessFile(new File(srcFile), "r");
        outFile = new FileOutputStream(new File(dstFile));
        int moovPos = 0;
        int mdatPos = 0;
        int moovSize = 0;
        int mdatSize = 0;
        byte[] boxSizeBuf = new byte[4];
        byte[] pathBuf = new byte[4];
        int boxSize;
        int dataSize;
        int bytesRead;
        int totalBytesRead = 0;
        int bytesWritten = 0;

        // First find the location and size of the moov and mdat boxes
        while (true) {
            try {
                boxSize = inFile.readInt();
                bytesRead = inFile.read(pathBuf);
                if (bytesRead != 4) {
                    Log.e(TAG, "Unexpected bytes read (path) " + bytesRead);
                    break;
                }
                String pathRead = new String(pathBuf, "UTF-8");
                dataSize = boxSize - 8;
                totalBytesRead += 8;
                if (pathRead.equals("moov")) {
                    moovPos = totalBytesRead - 8;
                    moovSize = boxSize;
                } else if (pathRead.equals("mdat")) {
                    mdatPos = totalBytesRead - 8;
                    mdatSize = boxSize;
                }
                totalBytesRead += inFile.skipBytes(dataSize);
            } catch (IOException e) {
                break;
            }
        }

        // Read the moov box into a buffer. This has to be patched up. Ug.
        inFile.seek(moovPos);
        byte[] moovBoxBuf = new byte[moovSize]; // This shouldn't be too big.
        bytesRead = inFile.read(moovBoxBuf);
        if (bytesRead != moovSize) {
            Log.e(TAG, "Couldn't read full moov box");
        }

        // Now locate the stco boxes (chunk offset box) inside the moov box and patch
        // them up. This ain't purdy.
        int pos = 0;
        while (pos < moovBoxBuf.length - 4) {
            if (moovBoxBuf[pos] == 0x73 && moovBoxBuf[pos + 1] == 0x74 &&
                    moovBoxBuf[pos + 2] == 0x63 && moovBoxBuf[pos + 3] == 0x6f) {
                int stcoPos = pos - 4;
                int stcoSize = byteArrayToInt(moovBoxBuf, stcoPos);
                patchStco(moovBoxBuf, stcoSize, stcoPos, moovSize);
            }
            pos++;
        }

        inFile.seek(0);
        byte[] buf = new byte[(int) mdatPos];
        // Write out everything before mdat
        inFile.read(buf);
        outFile.write(buf);

        // Write moov
        outFile.write(moovBoxBuf, 0, moovSize);

        // Write out mdat
        inFile.seek(mdatPos);
        bytesWritten = 0;
        while (bytesWritten < mdatSize) {
            int bytesRemaining = (int) mdatSize - bytesWritten;
            int bytesToRead = buf.length;
            if (bytesRemaining < bytesToRead) bytesToRead = bytesRemaining;
            bytesRead = inFile.read(buf, 0, bytesToRead);
            if (bytesRead > 0) {
                outFile.write(buf, 0, bytesRead);
                bytesWritten += bytesRead;
            } else {
                break;
            }
        }
    } catch (IOException e) {
        Log.e(TAG, e.getMessage());
    } finally {
        try {
            if (outFile != null) outFile.close();
            if (inFile != null) inFile.close();
        } catch (IOException e) {}
    }
}

private void patchStco(byte[] buf, int size, int pos, int moovSize) {
    Log.e(TAG, "stco " + pos + " size " + size);
    // We are inserting the moov box before the mdat box so all of
    // offsets in the stco box need to be increased by the size of the moov box. The stco
    // box is variable in length. 4 byte size, 4 byte path, 4 byte version, 4 byte flags
    // followed by a variable number of chunk offsets. So subtract off 16 from size then
    // divide result by 4 to get the number of chunk offsets to patch up.
    int chunkOffsetCount = (size - 16) / 4;
    int chunkPos = pos + 16;
    for (int i = 0; i < chunkOffsetCount; i++) {
        int chunkOffset = byteArrayToInt(buf, chunkPos);
        int newChunkOffset = chunkOffset + moovSize;
        intToByteArray(newChunkOffset, buf, chunkPos);
        chunkPos += 4;
    }
}

public static int byteArrayToInt(byte[] b, int offset)
{
    return   b[offset + 3] & 0xFF |
            (b[offset + 2] & 0xFF) << 8 |
            (b[offset + 1] & 0xFF) << 16 |
            (b[offset] & 0xFF) << 24;
}

public void intToByteArray(int a, byte[] buf, int offset)
{
    buf[offset] = (byte) ((a >> 24) & 0xFF);
    buf[offset + 1] = (byte) ((a >> 16) & 0xFF);
    buf[offset + 2] = (byte) ((a >> 8) & 0xFF);
    buf[offset + 3] = (byte) (a  & 0xFF);
}
.

다른 팁

현재 MediaMuxer는 유리한 MP4 파일을 생성하지 않습니다

https://software.intel.com/ko/ko에서 intel inde를 시도 할 수 있습니다. https://software.intel.com/en-us/articles/intel-inde-media-pack-for-android-tutorials .미디어 팩을 사용하여 네트워크를 통해 파일을 만들고 스트리밍하는 방법을 보여주는 샘플이 있습니다.

예를 들어 카메라 스트리밍의 경우 샘플 카메라색 이메이 activity.java

public void onCreate(Bundle icicle) {

    capture = new CameraCapture(new AndroidMediaObjectFactory(getApplicationContext()), progressListener);

    parameters = new StreamingParameters();
    parameters.Host = getString(R.string.streaming_server_default_ip);
    parameters.Port = Integer.parseInt(getString(R.string.streaming_server_default_port));
    parameters.ApplicationName = getString(R.string.streaming_server_default_app);
    parameters.StreamName = getString(R.string.streaming_server_default_stream);

    parameters.isToPublishAudio = false;
    parameters.isToPublishVideo = true;
}

public void startStreaming() {
    configureMediaStreamFormat();
    capture.setTargetVideoFormat(videoFormat);
    capture.setTargetAudioFormat(audioFormat);
    capture.setTargetConnection(prepareStreamingParams());
    capture.start();
}
.

파일 스트리밍이나 게임 프로세스 캡처 및 스트리밍에 대한 시뮬레이션 샘플이 있습니다

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top