Exemple #1
0
static int ffmpeg_frame_is_sync (codec_data_t *ifptr,
                                 uint8_t *buffer,
                                 uint32_t buflen,
                                 void *userdata)
{
    int ret;
    int ftype;
    uint32_t offset;
    ffmpeg_codec_t *ffmpeg = (ffmpeg_codec_t *)ifptr;
    switch (ffmpeg->m_codecId) {
    case CODEC_ID_H264:
        // look for idr nal
        do {
            uint8_t nal_type = h264_nal_unit_type(buffer);
            if (nal_type == H264_NAL_TYPE_SEQ_PARAM) return 1;
            //ffmpeg_message(LOG_DEBUG, "ffmpeg", "nal type %u", nal_type);
            if (h264_nal_unit_type_is_slice(nal_type)) {
                if (nal_type == H264_NAL_TYPE_IDR_SLICE) return 1;
#if 0
                uint8_t slice_type;
                if (h264_find_slice_type(buffer, buflen, &slice_type) >= 0) {
                    return H264_TYPE_IS_I(slice_type) ? 1 : 0;
                }
                return 0;
#else
                return 0;
#endif
            }
            offset = h264_find_next_start_code(buffer, buflen);
            buffer += offset;
            buflen -= offset;
        } while (offset != 0);
        break;
    case CODEC_ID_MPEG2VIDEO:
        // this would be for mpeg2
        ret = MP4AV_Mpeg3FindPictHdr(buffer, buflen, &ftype);
        ffmpeg_message(LOG_ERR, "ffmpeg", "ret %u type %u", ret, ftype);
        if (ret >= 0 && ftype == 1) {
            return 1;
        }
        break;
    case CODEC_ID_MPEG4: {
        uint8_t *vop = MP4AV_Mpeg4FindVop(buffer, buflen);
        if (vop == NULL) return 0;
        if (MP4AV_Mpeg4GetVopType(vop, buflen - (vop - buffer)) == VOP_TYPE_I)
            return 1;
    }
    break;
    default:
        // for every other, return that it is sync
        return 1;
    }
    return 0;
}
static void ParseH264 (uint8_t *bptr, uint32_t blen, 
		       uint32_t len_size, bool dump_off)
{
  uint8_t *fptr = bptr;
  while (blen > len_size) {
    uint32_t nal_len = 0;
    switch (len_size) {
    case 1: nal_len = *bptr; break;
    case 2: nal_len = (bptr[0] << 8) | bptr[1]; break;
    case 3: nal_len = (bptr[0] << 16) | (bptr[1] << 8) | bptr[2]; break;
    case 4: nal_len = (bptr[0] << 24) | (bptr[1] << 16) | (bptr[2] << 8) | bptr[3]; break;
    }
    bptr += len_size;
    blen -= len_size;
    uint8_t nal_type = *bptr & 0x1f;
    switch (nal_type) {
    case H264_NAL_TYPE_NON_IDR_SLICE: printf(" NIDR-"); break;
    case H264_NAL_TYPE_DP_A_SLICE: printf(" DPA-"); break;
    case H264_NAL_TYPE_DP_B_SLICE: printf(" DPB-"); break;
    case H264_NAL_TYPE_DP_C_SLICE: printf(" DPC-"); break;
    case H264_NAL_TYPE_IDR_SLICE: printf(" IDR-"); break;
    case H264_NAL_TYPE_SEI: printf(" SEI"); break;
    case H264_NAL_TYPE_SEQ_PARAM: printf(" SEQ"); break;
    case H264_NAL_TYPE_PIC_PARAM: printf(" PIC"); break;
    case H264_NAL_TYPE_ACCESS_UNIT: printf(" AU"); break;
    case H264_NAL_TYPE_END_OF_SEQ: printf(" EOS"); break;
    case H264_NAL_TYPE_END_OF_STREAM: printf(" EOST"); break;
    case H264_NAL_TYPE_FILLER_DATA: printf(" FILL"); break;
    default: printf(" UNK(0x%x)", nal_type); break;
    }
    if (h264_nal_unit_type_is_slice(nal_type)) {
      uint8_t slice_type;
      h264_find_slice_type(bptr, nal_len, &slice_type, true);
      printf("%s", h264_get_slice_name(slice_type));
    }
    uint32_t off =  bptr - fptr - len_size;
    if (dump_off) printf("(%u)", off);
    bptr += nal_len;
    if (nal_len > blen) {
      blen = 0;
    } else 
      blen -= nal_len;
  }
}
Exemple #3
0
bool CX264VideoEncoder::EncodeImage(
				      const u_int8_t* pY, 
				      const u_int8_t* pU, 
				      const u_int8_t* pV, 
	u_int32_t yStride, u_int32_t uvStride,
	bool wantKeyFrame, 
	Duration elapsedDuration,
	Timestamp srcFrameTimestamp)
{
  //debug_message("encoding at "U64, srcFrameTimestamp);
  m_push->Push(srcFrameTimestamp);
  if (m_vopBuffer == NULL) {
    m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize);
    if (m_vopBuffer == NULL) {
      error_message("Cannot malloc vop size");
      return false;
    }
  }
  m_count++;
  if (m_count >= m_key_frame_count) {
    wantKeyFrame = true;
    m_count = 0;
  }
#ifdef USE_OUR_YUV
  m_pic_input.img.plane[0] = (uint8_t *)pY;
  m_pic_input.img.i_stride[0] = yStride;
  m_pic_input.img.plane[1] = (uint8_t *)pU;
  m_pic_input.img.i_stride[1] = uvStride;
  m_pic_input.img.plane[2] = (uint8_t *)pV;
  m_pic_input.img.i_stride[2] = uvStride;
#else
  CopyYuv(pY, pU, pV, yStride, uvStride, uvStride,
	  m_pic_input.img.plane[0],m_pic_input.img.plane[1],m_pic_input.img.plane[2], 
	  m_pic_input.img.i_stride[0],m_pic_input.img.i_stride[1],m_pic_input.img.i_stride[2],
	  Profile()->m_videoWidth, Profile()->m_videoHeight);
#endif

  m_pic_input.i_type = wantKeyFrame ? X264_TYPE_IDR : X264_TYPE_AUTO;
  m_pic_input.i_pts = srcFrameTimestamp;

  x264_nal_t *nal;
  int i_nal;
  if (x264_encoder_encode(m_h, &nal, &i_nal, &m_pic_input, &m_pic_output) < 0) {
    error_message("x264_encoder_encode failed");
    return false;
  }
  CHECK_AND_FREE(m_nal_info);
  m_nal_info = (h264_nal_buf_t *)malloc(i_nal * sizeof(h264_nal_buf_t));
  uint8_t *vopBuffer = m_vopBuffer;
  int vopBufferLen = m_vopBufferLength;
  uint32_t loaded = 0;
  uint32_t nal_on = 0;

  // read the nals out of the encoder.  Nice...
  for (int ix = 0; ix < i_nal; ix++) {
    int i_size;
    bool skip = false;
    i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]);
    if (i_size > 0) {
      m_nal_info[nal_on].nal_length = i_size;
      m_nal_info[nal_on].nal_offset = loaded;
      m_nal_info[nal_on].nal_type = nal[ix].i_type;
      m_nal_info[nal_on].unique = false;
      uint32_t header = 0;
      if (h264_is_start_code(vopBuffer)) {
	header = vopBuffer[2] == 1 ? 3 : 4;
      }
      m_nal_info[nal_on].nal_length -= header;
      m_nal_info[nal_on].nal_offset += header;
      // we will send picture or sequence header through - let the
      // sinks decide to send or not
      if (skip == false) {
#ifdef DEBUG_H264
	uint8_t nal_type = nal[ix].i_type;
	if (h264_nal_unit_type_is_slice(nal_type)) {
	  uint8_t stype;
	  h264_find_slice_type(vopBuffer, i_size, &stype, true);
	  debug_message("nal %d - type %u slice type %u %d",
			ix, nal_type, stype, i_size);
	} else {
	  debug_message("nal %d - type %u %d", ix, nal_type, i_size);
	}
#endif
	nal_on++;
	loaded += i_size;
	vopBufferLen -= i_size;
	vopBuffer += i_size;
      } else {
#ifdef DEBUG_H264
	debug_message("skipped nal %u", nal[ix].i_type);
#endif
      }
    } else {
      error_message("Need to increase vop buffer size by %d", 
		    -i_size);
    }
  }
  m_nal_num = nal_on;
  m_vopBufferLength = loaded;
#ifdef DEBUG_H264
  debug_message("x264 loaded %d nals, %u len", 
		i_nal, loaded);
#endif
#ifdef OUTPUT_RAW
  if (m_vopBufferLength) {
    fwrite(m_vopBuffer, m_vopBufferLength, 1, m_outfile);
  }
#endif
	
  return true;
}
Exemple #4
0
static int ffmpeg_decode (codec_data_t *ptr,
                          frame_timestamp_t *pts,
                          int from_rtp,
                          int *sync_frame,
                          uint8_t *buffer,
                          uint32_t buflen,
                          void *ud)
{
    ffmpeg_codec_t *ffmpeg = (ffmpeg_codec_t *)ptr;
    uint32_t bytes_used = 0;
    int got_picture = 0;
    uint64_t ts = pts->msec_timestamp;

    //ffmpeg_message(LOG_ERR, "ffmpeg", "%u timestamp "U64, buflen, ts);
    if (ffmpeg->m_codec_opened == false) {
        // look for header, like above, and open it
        bool open_codec = true;
        switch (ffmpeg->m_codecId) {
        case CODEC_ID_H264:
            open_codec = ffmpeg_find_h264_size(ffmpeg, buffer, buflen);
            break;
        default:
            break;
        }
        if (open_codec) {
            if (avcodec_open(ffmpeg->m_c, ffmpeg->m_codec) < 0) {
                ffmpeg_message(LOG_CRIT, "ffmpeg", "failed to open codec");
                return buflen;
            }
            ffmpeg->m_codec_opened = true;
            ffmpeg_message(LOG_ERR, "ffmpeg", "opened codec");
        } else {
            ffmpeg_message(LOG_ERR, "ffmpeg", "no open %u "U64, buflen, ts);
            return buflen;
        }
    }

    // look and see if we have read the I frame.
    if (ffmpeg->m_got_i == false) {
        if (ffmpeg_frame_is_sync(ptr, buffer, buflen, NULL) == 0) {
            return buflen;
        }
        ffmpeg->m_got_i = true;
    }

    int ret;
    do {
        int local_got_picture;
        ret = avcodec_decode_video(ffmpeg->m_c,
                                   ffmpeg->m_picture,
                                   &local_got_picture,
                                   buffer + bytes_used,
                                   buflen - bytes_used);
        bytes_used += ret;
        //ffmpeg_message(LOG_CRIT, "ffmpeg", "used %d %d", ret, local_got_picture);
        got_picture |= local_got_picture;
    } while (ret != -1 && bytes_used < buflen);

    if (pts->timestamp_is_pts) {
        //ffmpeg_message(LOG_ERR, "ffmpeg", "pts timestamp "U64, ts);
        if (ffmpeg->m_codecId == CODEC_ID_MPEG2VIDEO) {
            if (ffmpeg->pts_convert.frame_rate == 0.0) {
                int have_mpeg2;
                uint32_t h, w;
                double bitrate, aspect_ratio;
                uint8_t profile;
                MP4AV_Mpeg3ParseSeqHdr(buffer, buflen,
                                       &have_mpeg2,
                                       &h, &w,
                                       &ffmpeg->pts_convert.frame_rate,
                                       &bitrate, &aspect_ratio,
                                       &profile);
            }

            int ftype;
            int header = MP4AV_Mpeg3FindPictHdr(buffer, buflen, &ftype);
            if (header >= 0) {
                uint16_t temp_ref = MP4AV_Mpeg3PictHdrTempRef(buffer + header);
                uint64_t ret;
                if (got_picture == 0 ||
                        mpeg3_find_dts_from_pts(&ffmpeg->pts_convert,
                                                ts,
                                                ftype,
                                                temp_ref,
                                                &ret) < 0) {
                    ffmpeg->have_cached_ts = false;
                    return buflen;
                }
#if 0
                ffmpeg->m_vft->log_msg(LOG_DEBUG, "ffmpeg", "pts "U64" dts "U64" temp %u type %u %u",
                                       ts, ret,
                                       temp_ref, ftype, got_picture);
#endif
                ts = ret;
                //	ffmpeg_message(LOG_ERR, "ffmpeg", "type %d ref %u "U64, ftype, temp_ref, ret);
            }
        } else if (ffmpeg->m_codecId == CODEC_ID_MPEG4) {
            uint8_t *vopstart = MP4AV_Mpeg4FindVop(buffer, buflen);
            if (vopstart) {
                int ftype = MP4AV_Mpeg4GetVopType(vopstart, buflen);
                uint64_t dts;
                if (MP4AV_calculate_dts_from_pts(&ffmpeg->pts_to_dts,
                                                 ts,
                                                 ftype,
                                                 &dts) < 0) {
                    ffmpeg->have_cached_ts = false;
#ifdef DEBUG_FFMPEG_PTS
                    ffmpeg_message(LOG_DEBUG, "ffmpeg", "type %d %d pts "U64" failed to calc",
                                   ftype, got_picture, ts);
#endif
                    return buflen;
                }
#ifdef DEBUG_FFMPEG_PTS
                ffmpeg_message(LOG_DEBUG, "ffmpeg", "type %d %d pts "U64" dts "U64,
                               ftype, got_picture, ts, dts);
#endif
                ts = dts;
            }
        } else if (ffmpeg->m_codecId == CODEC_ID_H264) {
            uint8_t *nal_ptr = buffer;
            uint32_t len = buflen;
            bool have_b_nal = false;
            do {
                if (h264_nal_unit_type_is_slice(h264_nal_unit_type(nal_ptr))) {
                    uint8_t slice_type;
                    if (h264_find_slice_type(nal_ptr, len, &slice_type, false) >= 0) {
                        have_b_nal = H264_TYPE_IS_B(slice_type);
                    }
                }
                uint32_t offset = h264_find_next_start_code(nal_ptr, len);
                if (offset == 0) {
                    len = 0;
                } else {
                    nal_ptr += offset;
                    len -= offset;
                }
            } while (len > 0 && have_b_nal == false);
            uint64_t dts;
            if (MP4AV_calculate_dts_from_pts(&ffmpeg->pts_to_dts,
                                             ts,
                                             have_b_nal ? VOP_TYPE_B : VOP_TYPE_P,
                                             &dts) < 0) {
                ffmpeg->have_cached_ts = false;
#ifdef DEBUG_FFMPEG_PTS
                ffmpeg_message(LOG_DEBUG, "ffmpeg", "pts "U64" failed to calc",
                               ts);
#endif
                return buflen;
            }
            ts = dts;
        }
    }
    if (got_picture != 0) {
        if (ffmpeg->m_video_initialized == false) {
            double aspect;
            if (ffmpeg->m_c->sample_aspect_ratio.den == 0) {
                aspect = 0.0; // don't have one
            } else {
                aspect = av_q2d(ffmpeg->m_c->sample_aspect_ratio);
            }
            if (ffmpeg->m_c->width == 0) {
                return buflen;
            }
            ffmpeg->m_vft->video_configure(ffmpeg->m_ifptr,
                                           ffmpeg->m_c->width,
                                           ffmpeg->m_c->height,
                                           VIDEO_FORMAT_YUV,
                                           aspect);
            ffmpeg->m_video_initialized = true;
        }

        if (ffmpeg->m_c->pix_fmt != PIX_FMT_YUV420P) {
            // convert the image from whatever it is to YUV 4:2:0
            AVPicture from, to;
            int ret;
            // get the buffer to copy into (put it right into the ring buffer)
            ret = ffmpeg->m_vft->video_get_buffer(ffmpeg->m_ifptr,
                                                  &to.data[0],
                                                  &to.data[1],
                                                  &to.data[2]);
            if (ret == 0) {
                return buflen;
            }
            // set up the AVPicture structures
            to.linesize[0] = ffmpeg->m_c->width;
            to.linesize[1] = ffmpeg->m_c->width / 2;
            to.linesize[2] = ffmpeg->m_c->width / 2;
            for (int ix = 0; ix < 4; ix++) {
                from.data[ix] = ffmpeg->m_picture->data[ix];
                from.linesize[ix] = ffmpeg->m_picture->linesize[ix];
            }

            img_convert(&to, PIX_FMT_YUV420P,
                        &from, ffmpeg->m_c->pix_fmt,
                        ffmpeg->m_c->width, ffmpeg->m_c->height);
            ffmpeg->m_vft->video_filled_buffer(ffmpeg->m_ifptr,
                                               ffmpeg->have_cached_ts ?
                                               ffmpeg->cached_ts : ts);
        } else {
            ffmpeg->m_vft->video_have_frame(ffmpeg->m_ifptr,
                                            ffmpeg->m_picture->data[0],
                                            ffmpeg->m_picture->data[1],
                                            ffmpeg->m_picture->data[2],
                                            ffmpeg->m_picture->linesize[0],
                                            ffmpeg->m_picture->linesize[1],
                                            ffmpeg->have_cached_ts ?
                                            ffmpeg->cached_ts : ts);
        }
        ffmpeg->cached_ts = ts;
    } else {
        ffmpeg->cached_ts = ts;
        ffmpeg->have_cached_ts = true;
    }
#ifdef DEBUG_FFMPEG_FRAME
    ffmpeg_message(LOG_DEBUG, "ffmpeg", "used %u of %u", bytes_used, buflen);
#endif
    return (buflen);
}