Пример #1
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);
}
Пример #2
0
static int mpeg2dec_decode (codec_data_t *ptr,
			    frame_timestamp_t *pts, 
			    int from_rtp,
			    int *sync_frame,
			    uint8_t *buffer, 
			    uint32_t buflen,
			    void *ud)
{
  mpeg2dec_codec_t *mpeg2dec = (mpeg2dec_codec_t *)ptr;
  mpeg2dec_t *decoder;
  const mpeg2_info_t *info;
  mpeg2_state_t state;
  uint64_t ts = pts->msec_timestamp;

  decoder = mpeg2dec->m_decoder;
  
#if 0
  mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "ts buflen %d "U64, buflen, ts);
  //if (mpeg2dec->m_did_pause != 0) 
 {
    for (uint32_t ix = 0; ix < buflen + 3; ix++) {
      if (buffer[ix] == 0 &&
	  buffer[ix + 1] == 0 &&
	  buffer[ix + 2] == 1) {
	mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "index %d - value %x %x %x", 
			      ix, buffer[ix + 3], buffer[ix + 4],
			      buffer[ix + 5]);
      }
    }
  }
#endif

 info = mpeg2_info(decoder);
 bool passed_buffer = false;
 bool finished_buffer = false;
 do {
   state = mpeg2_parse(decoder);
   //mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "state %d", state);
   const mpeg2_sequence_t *sequence;
   sequence = info->sequence;
   switch (state) {
   case STATE_BUFFER:
     if (passed_buffer == false) {
       mpeg2_buffer(decoder, buffer, buffer + buflen);
       passed_buffer = true;
     } else {
       finished_buffer = true;
     } 
     break;
   case STATE_SEQUENCE: {
     if (mpeg2dec->m_video_initialized == 0) {
       mpeg2dec->m_h = sequence->height;
       mpeg2dec->m_w = sequence->width;
       int have_mpeg2;
       uint32_t height;
       uint32_t width;
       double frame_rate;
       double bitrate;
       double aspect_ratio;
       uint8_t profile;
       if (MP4AV_Mpeg3ParseSeqHdr(buffer, 
				  buflen,
				  &have_mpeg2, 
				  &height, 
				  &width, 
				  &frame_rate,
				  &bitrate, 
				  &aspect_ratio,
				  &profile) < 0) {
	 
	 mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "pix w %u pix h %u", 
				  sequence->pixel_width, 
				  sequence->pixel_height);
	 aspect_ratio = sequence->pixel_width;
	 aspect_ratio *= mpeg2dec->m_w;
	 aspect_ratio /= (double)(sequence->pixel_height * mpeg2dec->m_h);
       }
       mpeg2dec->pts_convert.frame_rate = frame_rate;
       mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "%ux%u aspect %g", 
				mpeg2dec->m_w, mpeg2dec->m_h, 
				aspect_ratio);
       mpeg2dec->m_vft->video_configure(mpeg2dec->m_ifptr, 
					mpeg2dec->m_w,
					mpeg2dec->m_h,
					VIDEO_FORMAT_YUV,
					aspect_ratio);
       mpeg2dec->m_video_initialized = 1;
     }
     break;
    }
   case STATE_SLICE:
   case STATE_END:
   case STATE_INVALID_END:  
     // INVALID_END state means they found a new sequence header, with a 
     // new size
     
#ifdef DEBUG_MPEG2DEC_FRAME
     mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "frame "U64" decoded", 
			  mpeg2dec->cached_ts);
#endif
     if (info->display_fbuf) {
       mpeg2dec->m_vft->video_have_frame(mpeg2dec->m_ifptr,
					 info->display_fbuf->buf[0],
					 info->display_fbuf->buf[1],
					 info->display_fbuf->buf[2],
					 sequence->width, 
					 sequence->chroma_width,
					 mpeg2dec->m_cached_ts_invalid ? ts :
					 mpeg2dec->cached_ts);
     }
     break;
   case STATE_SEQUENCE_REPEATED: // we don't care here
   case STATE_GOP: 
   case STATE_PICTURE:
   case STATE_SLICE_1ST:
   case STATE_PICTURE_2ND:
   case STATE_INVALID: //
   default:
     break;
   } 
 } while (finished_buffer == false);
 
 mpeg2dec->m_cached_ts_invalid = false;
 if (pts->timestamp_is_pts) {
   if (info->current_picture == NULL ||
       mpeg3_find_dts_from_pts(&mpeg2dec->pts_convert,
			       ts,
			       info->current_picture->flags & PIC_MASK_CODING_TYPE, 
			       info->current_picture->temporal_reference,
			       &mpeg2dec->cached_ts) < 0) {
     mpeg2dec->m_cached_ts_invalid = true;
   }
#if 0
   mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "pts "U64" dts "U64" temp %u type %u", 
			    pts->msec_timestamp, mpeg2dec->cached_ts, 
			    info->current_picture->temporal_reference, 
			    info->current_picture->flags & PIC_MASK_CODING_TYPE);
#endif

 } else {
   mpeg2dec->cached_ts = ts;
 }
 return (buflen);
}