Пример #1
0
void MPEGProgramStreamParser::parsePackHeader()
{
#ifdef DEBUG
    fprintf(stderr, "parsing pack header\n");
    fflush(stderr);
#endif
    unsigned first4Bytes;
    while (1)
    {
        first4Bytes = test4Bytes();

        // We're supposed to have a pack header here, but check also for
        // a system header or a PES packet, just in case:
        if (first4Bytes == PACK_START_CODE)
        {
            skipBytes(4);
            break;
        }
        else if (first4Bytes == SYSTEM_HEADER_START_CODE)
        {
#ifdef DEBUG
            fprintf(stderr, "found system header instead of pack header\n");
#endif
            setParseState(PARSING_SYSTEM_HEADER);
            return;
        }
        else if (isPacketStartCode(first4Bytes))
        {
#ifdef DEBUG
            fprintf(stderr, "found packet start code 0x%02x instead of pack header\n", first4Bytes);
#endif
            setParseState(PARSING_PES_PACKET);
            return;
        }

        setParseState(PARSING_PACK_HEADER); // ensures we progress over bad data
        if ((first4Bytes & 0xFF) > 1) // a system code definitely doesn't start here
        {
            skipBytes(4);
        }
        else
        {
            skipBytes(1);
        }
    }

    // The size of the pack header differs depending on whether it's
    // MPEG-1 or MPEG-2.  The next byte tells us this:
    unsigned char nextByte = get1Byte();
    MPEG1or2Demux::SCR &scr = fUsingSource->fLastSeenSCR; // alias
    if ((nextByte & 0xF0) == 0x20) // MPEG-1
    {
        fUsingSource->fMPEGversion = 1;
        scr.highBit =  (nextByte & 0x08) >> 3;
        scr.remainingBits = (nextByte & 0x06) << 29;
        unsigned next4Bytes = get4Bytes();
        scr.remainingBits |= (next4Bytes & 0xFFFE0000) >> 2;
        scr.remainingBits |= (next4Bytes & 0x0000FFFE) >> 1;
        scr.extension = 0;
        scr.isValid = True;
        skipBits(24);

#if defined(DEBUG_TIMESTAMPS) || defined(DEBUG_SCR_TIMESTAMPS)
        fprintf(stderr, "pack hdr system_clock_reference_base: 0x%x",
                scr.highBit);
        fprintf(stderr, "%08x\n", scr.remainingBits);
#endif
    }
unsigned MPEG1or2VideoStreamParser::parseGOPHeader(Boolean haveSeenStartCode)
{
    // First check whether we should insert a previously-saved
    // 'video_sequence_header' here:
    if (needToUseSavedVSH()) return useSavedVSH();

#ifdef DEBUG
    fprintf(stderr, "parsing GOP header\n");
#endif
    unsigned first4Bytes;
    if (!haveSeenStartCode)
    {
        while ((first4Bytes = test4Bytes()) != GROUP_START_CODE)
        {
#ifdef DEBUG
            fprintf(stderr, "ignoring non GOP start code: 0x%08x\n", first4Bytes);
#endif
            get1Byte();
            setParseState(PARSING_GOP_HEADER);
            // ensures we progress over bad data
        }
        first4Bytes = get4Bytes();
    }
    else
    {
        // We've already seen the GROUP_START_CODE
        first4Bytes = GROUP_START_CODE;
    }
    save4Bytes(first4Bytes);

    // Next, extract the (25-bit) time code from the next 4 bytes:
    unsigned next4Bytes = get4Bytes();
    unsigned time_code = (next4Bytes & 0xFFFFFF80) >> (32 - 25);
#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS)
    Boolean drop_frame_flag     = (time_code & 0x01000000) != 0;
#endif
    unsigned time_code_hours    = (time_code & 0x00F80000) >> 19;
    unsigned time_code_minutes  = (time_code & 0x0007E000) >> 13;
    unsigned time_code_seconds  = (time_code & 0x00000FC0) >> 6;
    unsigned time_code_pictures = (time_code & 0x0000003F);
#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS)
    fprintf(stderr, "time_code: 0x%07x, drop_frame %d, hours %d, minutes %d, seconds %d, pictures %d\n", time_code, drop_frame_flag, time_code_hours, time_code_minutes, time_code_seconds, time_code_pictures);
#endif
#ifdef DEBUG
    Boolean closed_gop  = (next4Bytes & 0x00000040) != 0;
    Boolean broken_link = (next4Bytes & 0x00000020) != 0;
    fprintf(stderr, "closed_gop: %d, broken_link: %d\n", closed_gop, broken_link);
#endif

    // Now, copy all bytes that we see, up until we reach a PICTURE_START_CODE:
    do
    {
        saveToNextCode(next4Bytes);
    }
    while (next4Bytes != PICTURE_START_CODE);

    // Record the time code:
    usingSource()->setTimeCode(time_code_hours, time_code_minutes,
                               time_code_seconds, time_code_pictures,
                               fPicturesSinceLastGOP);

    fPicturesSinceLastGOP = 0;

    // Compute this frame's timestamp:
    usingSource()->computePresentationTime(0);

    setParseState(PARSING_PICTURE_HEADER);

    return curFrameSize();
}
Пример #3
0
WAVAudioFileSource::WAVAudioFileSource(UsageEnvironment& env, FILE* fid)
  : AudioInputDevice(env, 0, 0, 0, 0)/* set the real parameters later */,
    fFid(fid), fLastPlayTime(0), fWAVHeaderSize(0), fFileSize(0), fScaleFactor(1),
    fLimitNumBytesToStream(False), fNumBytesToStream(0), fAudioFormat(WA_UNKNOWN) {
  // Check the WAV file header for validity.
  // Note: The following web pages contain info about the WAV format:
  // http://www.ringthis.com/dev/wave_format.htm
  // http://www.lightlink.com/tjweber/StripWav/Canon.html
  // http://www.wotsit.org/list.asp?al=W

  Boolean success = False; // until we learn otherwise
  do {
    // RIFF Chunk:
    if (nextc != 'R' || nextc != 'I' || nextc != 'F' || nextc != 'F') break;
    if (!skipBytes(fid, 4)) break;
    if (nextc != 'W' || nextc != 'A' || nextc != 'V' || nextc != 'E') break;

    // FORMAT Chunk:
    if (nextc != 'f' || nextc != 'm' || nextc != 't' || nextc != ' ') break;
    unsigned formatLength;
    if (!get4Bytes(fid, formatLength)) break;
    unsigned short audioFormat;
    if (!get2Bytes(fid, audioFormat)) break;

    fAudioFormat = (unsigned char)audioFormat;
    if (fAudioFormat != WA_PCM && fAudioFormat != WA_PCMA && fAudioFormat != WA_PCMU && fAudioFormat != WA_IMA_ADPCM) {
      // It's a format that we don't (yet) understand
      env.setResultMsg("Audio format is not one that we handle (PCM/PCMU/PCMA or IMA ADPCM)");
      break;
    }
    unsigned short numChannels;
    if (!get2Bytes(fid, numChannels)) break;
    fNumChannels = (unsigned char)numChannels;
    if (fNumChannels < 1 || fNumChannels > 2) { // invalid # channels
      char errMsg[100];
      sprintf(errMsg, "Bad # channels: %d", fNumChannels);
      env.setResultMsg(errMsg);
      break;
    }
    if (!get4Bytes(fid, fSamplingFrequency)) break;
    if (fSamplingFrequency == 0) {
      env.setResultMsg("Bad sampling frequency: 0");
      break;
    }
    if (!skipBytes(fid, 6)) break; // "nAvgBytesPerSec" (4 bytes) + "nBlockAlign" (2 bytes)
    unsigned short bitsPerSample;
    if (!get2Bytes(fid, bitsPerSample)) break;
    fBitsPerSample = (unsigned char)bitsPerSample;
    if (fBitsPerSample == 0) {
      env.setResultMsg("Bad bits-per-sample: 0");
      break;
    }
    if (!skipBytes(fid, formatLength - 16)) break;

    // FACT chunk (optional):
    int c = nextc;
    if (c == 'f') {
      if (nextc != 'a' || nextc != 'c' || nextc != 't') break;
      unsigned factLength;
      if (!get4Bytes(fid, factLength)) break;
      if (!skipBytes(fid, factLength)) break;
      c = nextc;
    }

    // DATA Chunk:
    if (c != 'd' || nextc != 'a' || nextc != 't' || nextc != 'a') break;
    if (!skipBytes(fid, 4)) break;

    // The header is good; the remaining data are the sample bytes.
    fWAVHeaderSize = ftell(fid);
    success = True;
  } while (0);

  if (!success) {
    env.setResultMsg("Bad WAV file format");
    // Set "fBitsPerSample" to zero, to indicate failure:
    fBitsPerSample = 0;
    return;
  }

  fPlayTimePerSample = 1e6/(double)fSamplingFrequency;

  // Although PCM is a sample-based format, we group samples into
  // 'frames' for efficient delivery to clients.  Set up our preferred
  // frame size to be close to 20 ms, if possible, but always no greater
  // than 1400 bytes (to ensure that it will fit in a single RTP packet)
  unsigned maxSamplesPerFrame = (1400*8)/(fNumChannels*fBitsPerSample);
  unsigned desiredSamplesPerFrame = (unsigned)(0.02*fSamplingFrequency);
  unsigned samplesPerFrame = desiredSamplesPerFrame < maxSamplesPerFrame ? desiredSamplesPerFrame : maxSamplesPerFrame;
  fPreferredFrameSize = (samplesPerFrame*fNumChannels*fBitsPerSample)/8;
}
unsigned MPEG1or2VideoStreamParser
::parseVideoSequenceHeader(Boolean haveSeenStartCode)
{
#ifdef DEBUG
    fprintf(stderr, "parsing video sequence header\n");
#endif
    unsigned first4Bytes;
    if (!haveSeenStartCode)
    {
        while ((first4Bytes = test4Bytes()) != VIDEO_SEQUENCE_HEADER_START_CODE)
        {
#ifdef DEBUG
            fprintf(stderr, "ignoring non video sequence header: 0x%08x\n", first4Bytes);
#endif
            get1Byte();
            setParseState(PARSING_VIDEO_SEQUENCE_HEADER);
            // ensures we progress over bad data
        }
        first4Bytes = get4Bytes();
    }
    else
    {
        // We've already seen the start code
        first4Bytes = VIDEO_SEQUENCE_HEADER_START_CODE;
    }
    save4Bytes(first4Bytes);

    // Next, extract the size and rate parameters from the next 8 bytes
    unsigned paramWord1 = get4Bytes();
    save4Bytes(paramWord1);
    unsigned next4Bytes = get4Bytes();
#ifdef DEBUG
    unsigned short horizontal_size_value   = (paramWord1 & 0xFFF00000) >> (32 - 12);
    unsigned short vertical_size_value     = (paramWord1 & 0x000FFF00) >> 8;
    unsigned char aspect_ratio_information = (paramWord1 & 0x000000F0) >> 4;
#endif
    unsigned char frame_rate_code          = (paramWord1 & 0x0000000F);
    usingSource()->fFrameRate = frameRateFromCode[frame_rate_code];
#ifdef DEBUG
    unsigned bit_rate_value                = (next4Bytes & 0xFFFFC000) >> (32 - 18);
    unsigned vbv_buffer_size_value         = (next4Bytes & 0x00001FF8) >> 3;
    fprintf(stderr, "horizontal_size_value: %d, vertical_size_value: %d, aspect_ratio_information: %d, frame_rate_code: %d (=>%f fps), bit_rate_value: %d (=>%d bps), vbv_buffer_size_value: %d\n", horizontal_size_value, vertical_size_value, aspect_ratio_information, frame_rate_code, usingSource()->fFrameRate, bit_rate_value, bit_rate_value * 400, vbv_buffer_size_value);
#endif

    // Now, copy all bytes that we see, up until we reach a GROUP_START_CODE
    // or a PICTURE_START_CODE:
    do
    {
        saveToNextCode(next4Bytes);
    }
    while (next4Bytes != GROUP_START_CODE && next4Bytes != PICTURE_START_CODE);

    setParseState((next4Bytes == GROUP_START_CODE)
                  ? PARSING_GOP_HEADER_SEEN_CODE : PARSING_PICTURE_HEADER);

    // Compute this frame's timestamp by noting how many pictures we've seen
    // since the last GOP header:
    usingSource()->computePresentationTime(fPicturesSinceLastGOP);

    // Save this video_sequence_header, in case we need to insert a copy
    // into the stream later:
    saveCurrentVSH();

    return curFrameSize();
}
Пример #5
0
WAVAudioFileSource::WAVAudioFileSource(UsageEnvironment& env, FILE* fid)
  : AudioInputDevice(env, 0, 0, 0, 0)/* set the real parameters later */,
    fFid(fid), fFidIsSeekable(False), fLastPlayTime(0), fHaveStartedReading(False), fWAVHeaderSize(0), fFileSize(0),
    fScaleFactor(1), fLimitNumBytesToStream(False), fNumBytesToStream(0), fAudioFormat(WA_UNKNOWN) {
  // Check the WAV file header for validity.
  // Note: The following web pages contain info about the WAV format:
  // http://www.ringthis.com/dev/wave_format.htm
  // http://www.lightlink.com/tjweber/StripWav/Canon.html
  // http://www.onicos.com/staff/iz/formats/wav.html

  Boolean success = False; // until we learn otherwise
  do {
    // RIFF Chunk:
    if (nextc != 'R' || nextc != 'I' || nextc != 'F' || nextc != 'F') break;
    if (!skipBytes(fid, 4)) break;
    if (nextc != 'W' || nextc != 'A' || nextc != 'V' || nextc != 'E') break;

    // Skip over any chunk that's not a FORMAT ('fmt ') chunk:
    u_int32_t tmp;
    if (!get4Bytes(fid, tmp)) break;
    if (tmp != 0x20746d66/*'fmt ', little-endian*/) {
      // Skip this chunk:
      if (!get4Bytes(fid, tmp)) break;
      if (!skipBytes(fid, tmp)) break;
    }

    // FORMAT Chunk (the 4-byte header code has already been parsed):
    unsigned formatLength;
    if (!get4Bytes(fid, formatLength)) break;
    unsigned short audioFormat;
    if (!get2Bytes(fid, audioFormat)) break;

    fAudioFormat = (unsigned char)audioFormat;
    if (fAudioFormat != WA_PCM && fAudioFormat != WA_PCMA && fAudioFormat != WA_PCMU && fAudioFormat != WA_IMA_ADPCM) {
      // It's a format that we don't (yet) understand
      env.setResultMsg("Audio format is not one that we handle (PCM/PCMU/PCMA or IMA ADPCM)");
      break;
    }
    unsigned short numChannels;
    if (!get2Bytes(fid, numChannels)) break;
    fNumChannels = (unsigned char)numChannels;
    if (fNumChannels < 1 || fNumChannels > 2) { // invalid # channels
      char errMsg[100];
      sprintf(errMsg, "Bad # channels: %d", fNumChannels);
      env.setResultMsg(errMsg);
      break;
    }
    if (!get4Bytes(fid, fSamplingFrequency)) break;
    if (fSamplingFrequency == 0) {
      env.setResultMsg("Bad sampling frequency: 0");
      break;
    }
    if (!skipBytes(fid, 6)) break; // "nAvgBytesPerSec" (4 bytes) + "nBlockAlign" (2 bytes)
    unsigned short bitsPerSample;
    if (!get2Bytes(fid, bitsPerSample)) break;
    fBitsPerSample = (unsigned char)bitsPerSample;
    if (fBitsPerSample == 0) {
      env.setResultMsg("Bad bits-per-sample: 0");
      break;
    }
    if (!skipBytes(fid, formatLength - 16)) break;

    // FACT chunk (optional):
    int c = nextc;
    if (c == 'f') {
      if (nextc != 'a' || nextc != 'c' || nextc != 't') break;
      unsigned factLength;
      if (!get4Bytes(fid, factLength)) break;
      if (!skipBytes(fid, factLength)) break;
      c = nextc;
    }

    // DATA Chunk:
    if (c != 'd' || nextc != 'a' || nextc != 't' || nextc != 'a') break;
    if (!skipBytes(fid, 4)) break;

    // The header is good; the remaining data are the sample bytes.
    fWAVHeaderSize = (unsigned)TellFile64(fid);
    success = True;
  } while (0);

  if (!success) {
    env.setResultMsg("Bad WAV file format");
    // Set "fBitsPerSample" to zero, to indicate failure:
    fBitsPerSample = 0;
    return;
  }

  fPlayTimePerSample = 1e6/(double)fSamplingFrequency;

  // Although PCM is a sample-based format, we group samples into
  // 'frames' for efficient delivery to clients.  Set up our preferred
  // frame size to be close to 20 ms, if possible, but always no greater
  // than 1400 bytes (to ensure that it will fit in a single RTP packet)
  unsigned maxSamplesPerFrame = (1400*8)/(fNumChannels*fBitsPerSample);
  unsigned desiredSamplesPerFrame = (unsigned)(0.02*fSamplingFrequency);
  unsigned samplesPerFrame = desiredSamplesPerFrame < maxSamplesPerFrame ? desiredSamplesPerFrame : maxSamplesPerFrame;
  fPreferredFrameSize = (samplesPerFrame*fNumChannels*fBitsPerSample)/8;

  fFidIsSeekable = FileIsSeekable(fFid);
#ifndef READ_FROM_FILES_SYNCHRONOUSLY
  // Now that we've finished reading the WAV header, all future reads (of audio samples) from the file will be asynchronous:
  makeSocketNonBlocking(fileno(fFid));
#endif
}