1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/ffmpeg/ffmpeg_common.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "media/base/decoder_buffer.h"
13 #include "media/base/video_frame.h"
14 #include "media/base/video_util.h"
18 // Why FF_INPUT_BUFFER_PADDING_SIZE? FFmpeg assumes all input buffers are
19 // padded. Check here to ensure FFmpeg only receives data padded to its
21 COMPILE_ASSERT(DecoderBuffer::kPaddingSize
>= FF_INPUT_BUFFER_PADDING_SIZE
,
22 decoder_buffer_padding_size_does_not_fit_ffmpeg_requirement
);
24 // Alignment requirement by FFmpeg for input and output buffers. This need to
25 // be updated to match FFmpeg when it changes.
26 #if defined(ARCH_CPU_ARM_FAMILY)
27 static const int kFFmpegBufferAddressAlignment
= 16;
29 static const int kFFmpegBufferAddressAlignment
= 32;
32 // Check here to ensure FFmpeg only receives data aligned to its specifications.
34 DecoderBuffer::kAlignmentSize
>= kFFmpegBufferAddressAlignment
&&
35 DecoderBuffer::kAlignmentSize
% kFFmpegBufferAddressAlignment
== 0,
36 decoder_buffer_alignment_size_does_not_fit_ffmpeg_requirement
);
38 // Allows faster SIMD YUV convert. Also, FFmpeg overreads/-writes occasionally.
39 // See video_get_buffer() in libavcodec/utils.c.
40 static const int kFFmpegOutputBufferPaddingSize
= 16;
42 COMPILE_ASSERT(VideoFrame::kFrameSizePadding
>= kFFmpegOutputBufferPaddingSize
,
43 video_frame_padding_size_does_not_fit_ffmpeg_requirement
);
46 VideoFrame::kFrameAddressAlignment
>= kFFmpegBufferAddressAlignment
&&
47 VideoFrame::kFrameAddressAlignment
% kFFmpegBufferAddressAlignment
== 0,
48 video_frame_address_alignment_does_not_fit_ffmpeg_requirement
);
50 static const AVRational kMicrosBase
= { 1, base::Time::kMicrosecondsPerSecond
};
52 base::TimeDelta
ConvertFromTimeBase(const AVRational
& time_base
,
54 int64 microseconds
= av_rescale_q(timestamp
, time_base
, kMicrosBase
);
55 return base::TimeDelta::FromMicroseconds(microseconds
);
58 int64
ConvertToTimeBase(const AVRational
& time_base
,
59 const base::TimeDelta
& timestamp
) {
60 return av_rescale_q(timestamp
.InMicroseconds(), kMicrosBase
, time_base
);
63 // Converts an FFmpeg audio codec ID into its corresponding supported codec id.
64 static AudioCodec
CodecIDToAudioCodec(AVCodecID codec_id
) {
70 case AV_CODEC_ID_VORBIS
:
72 case AV_CODEC_ID_PCM_U8
:
73 case AV_CODEC_ID_PCM_S16LE
:
74 case AV_CODEC_ID_PCM_S24LE
:
75 case AV_CODEC_ID_PCM_F32LE
:
77 case AV_CODEC_ID_PCM_S16BE
:
78 return kCodecPCM_S16BE
;
79 case AV_CODEC_ID_PCM_S24BE
:
80 return kCodecPCM_S24BE
;
81 case AV_CODEC_ID_FLAC
:
83 case AV_CODEC_ID_AMR_NB
:
85 case AV_CODEC_ID_AMR_WB
:
87 case AV_CODEC_ID_GSM_MS
:
89 case AV_CODEC_ID_PCM_ALAW
:
90 return kCodecPCM_ALAW
;
91 case AV_CODEC_ID_PCM_MULAW
:
92 return kCodecPCM_MULAW
;
93 case AV_CODEC_ID_OPUS
:
96 DVLOG(1) << "Unknown audio CodecID: " << codec_id
;
98 return kUnknownAudioCodec
;
101 static AVCodecID
AudioCodecToCodecID(AudioCodec audio_codec
,
102 SampleFormat sample_format
) {
103 switch (audio_codec
) {
105 return AV_CODEC_ID_AAC
;
107 return AV_CODEC_ID_MP3
;
109 switch (sample_format
) {
110 case kSampleFormatU8
:
111 return AV_CODEC_ID_PCM_U8
;
112 case kSampleFormatS16
:
113 return AV_CODEC_ID_PCM_S16LE
;
114 case kSampleFormatS32
:
115 return AV_CODEC_ID_PCM_S24LE
;
116 case kSampleFormatF32
:
117 return AV_CODEC_ID_PCM_F32LE
;
119 DVLOG(1) << "Unsupported sample format: " << sample_format
;
122 case kCodecPCM_S16BE
:
123 return AV_CODEC_ID_PCM_S16BE
;
124 case kCodecPCM_S24BE
:
125 return AV_CODEC_ID_PCM_S24BE
;
127 return AV_CODEC_ID_VORBIS
;
129 return AV_CODEC_ID_FLAC
;
131 return AV_CODEC_ID_AMR_NB
;
133 return AV_CODEC_ID_AMR_WB
;
135 return AV_CODEC_ID_GSM_MS
;
137 return AV_CODEC_ID_PCM_ALAW
;
138 case kCodecPCM_MULAW
:
139 return AV_CODEC_ID_PCM_MULAW
;
141 return AV_CODEC_ID_OPUS
;
143 DVLOG(1) << "Unknown AudioCodec: " << audio_codec
;
145 return AV_CODEC_ID_NONE
;
148 // Converts an FFmpeg video codec ID into its corresponding supported codec id.
149 static VideoCodec
CodecIDToVideoCodec(AVCodecID codec_id
) {
151 case AV_CODEC_ID_H264
:
153 case AV_CODEC_ID_THEORA
:
155 case AV_CODEC_ID_MPEG4
:
157 case AV_CODEC_ID_VP8
:
159 case AV_CODEC_ID_VP9
:
162 DVLOG(1) << "Unknown video CodecID: " << codec_id
;
164 return kUnknownVideoCodec
;
167 static AVCodecID
VideoCodecToCodecID(VideoCodec video_codec
) {
168 switch (video_codec
) {
170 return AV_CODEC_ID_H264
;
172 return AV_CODEC_ID_THEORA
;
174 return AV_CODEC_ID_MPEG4
;
176 return AV_CODEC_ID_VP8
;
178 return AV_CODEC_ID_VP9
;
180 DVLOG(1) << "Unknown VideoCodec: " << video_codec
;
182 return AV_CODEC_ID_NONE
;
185 static VideoCodecProfile
ProfileIDToVideoCodecProfile(int profile
) {
186 // Clear out the CONSTRAINED & INTRA flags which are strict subsets of the
187 // corresponding profiles with which they're used.
188 profile
&= ~FF_PROFILE_H264_CONSTRAINED
;
189 profile
&= ~FF_PROFILE_H264_INTRA
;
191 case FF_PROFILE_H264_BASELINE
:
192 return H264PROFILE_BASELINE
;
193 case FF_PROFILE_H264_MAIN
:
194 return H264PROFILE_MAIN
;
195 case FF_PROFILE_H264_EXTENDED
:
196 return H264PROFILE_EXTENDED
;
197 case FF_PROFILE_H264_HIGH
:
198 return H264PROFILE_HIGH
;
199 case FF_PROFILE_H264_HIGH_10
:
200 return H264PROFILE_HIGH10PROFILE
;
201 case FF_PROFILE_H264_HIGH_422
:
202 return H264PROFILE_HIGH422PROFILE
;
203 case FF_PROFILE_H264_HIGH_444_PREDICTIVE
:
204 return H264PROFILE_HIGH444PREDICTIVEPROFILE
;
206 DVLOG(1) << "Unknown profile id: " << profile
;
208 return VIDEO_CODEC_PROFILE_UNKNOWN
;
211 static int VideoCodecProfileToProfileID(VideoCodecProfile profile
) {
213 case H264PROFILE_BASELINE
:
214 return FF_PROFILE_H264_BASELINE
;
215 case H264PROFILE_MAIN
:
216 return FF_PROFILE_H264_MAIN
;
217 case H264PROFILE_EXTENDED
:
218 return FF_PROFILE_H264_EXTENDED
;
219 case H264PROFILE_HIGH
:
220 return FF_PROFILE_H264_HIGH
;
221 case H264PROFILE_HIGH10PROFILE
:
222 return FF_PROFILE_H264_HIGH_10
;
223 case H264PROFILE_HIGH422PROFILE
:
224 return FF_PROFILE_H264_HIGH_422
;
225 case H264PROFILE_HIGH444PREDICTIVEPROFILE
:
226 return FF_PROFILE_H264_HIGH_444_PREDICTIVE
;
228 DVLOG(1) << "Unknown VideoCodecProfile: " << profile
;
230 return FF_PROFILE_UNKNOWN
;
233 SampleFormat
AVSampleFormatToSampleFormat(AVSampleFormat sample_format
) {
234 switch (sample_format
) {
235 case AV_SAMPLE_FMT_U8
:
236 return kSampleFormatU8
;
237 case AV_SAMPLE_FMT_S16
:
238 return kSampleFormatS16
;
239 case AV_SAMPLE_FMT_S32
:
240 return kSampleFormatS32
;
241 case AV_SAMPLE_FMT_FLT
:
242 return kSampleFormatF32
;
243 case AV_SAMPLE_FMT_S16P
:
244 return kSampleFormatPlanarS16
;
245 case AV_SAMPLE_FMT_FLTP
:
246 return kSampleFormatPlanarF32
;
248 DVLOG(1) << "Unknown AVSampleFormat: " << sample_format
;
250 return kUnknownSampleFormat
;
253 static AVSampleFormat
SampleFormatToAVSampleFormat(SampleFormat sample_format
) {
254 switch (sample_format
) {
255 case kSampleFormatU8
:
256 return AV_SAMPLE_FMT_U8
;
257 case kSampleFormatS16
:
258 return AV_SAMPLE_FMT_S16
;
259 case kSampleFormatS32
:
260 return AV_SAMPLE_FMT_S32
;
261 case kSampleFormatF32
:
262 return AV_SAMPLE_FMT_FLT
;
263 case kSampleFormatPlanarS16
:
264 return AV_SAMPLE_FMT_S16P
;
265 case kSampleFormatPlanarF32
:
266 return AV_SAMPLE_FMT_FLTP
;
268 DVLOG(1) << "Unknown SampleFormat: " << sample_format
;
270 return AV_SAMPLE_FMT_NONE
;
273 void AVCodecContextToAudioDecoderConfig(
274 const AVCodecContext
* codec_context
,
276 AudioDecoderConfig
* config
,
278 DCHECK_EQ(codec_context
->codec_type
, AVMEDIA_TYPE_AUDIO
);
280 AudioCodec codec
= CodecIDToAudioCodec(codec_context
->codec_id
);
282 SampleFormat sample_format
=
283 AVSampleFormatToSampleFormat(codec_context
->sample_fmt
);
285 ChannelLayout channel_layout
= ChannelLayoutToChromeChannelLayout(
286 codec_context
->channel_layout
, codec_context
->channels
);
288 int sample_rate
= codec_context
->sample_rate
;
289 if (codec
== kCodecOpus
) {
290 // |codec_context->sample_fmt| is not set by FFmpeg because Opus decoding is
291 // not enabled in FFmpeg. It doesn't matter what value is set here, so long
292 // as it's valid, the true sample format is selected inside the decoder.
293 sample_format
= kSampleFormatF32
;
295 // Always use 48kHz for OPUS. Technically we should match to the highest
296 // supported hardware sample rate among [8, 12, 16, 24, 48] kHz, but we
297 // don't know the hardware sample rate at this point and those rates are
298 // rarely used for output. See the "Input Sample Rate" section of the spec:
299 // http://tools.ietf.org/html/draft-terriberry-oggopus-01#page-11
303 base::TimeDelta seek_preroll
;
304 if (codec_context
->seek_preroll
> 0) {
305 seek_preroll
= base::TimeDelta::FromMicroseconds(
306 codec_context
->seek_preroll
* 1000000.0 / codec_context
->sample_rate
);
309 config
->Initialize(codec
,
313 codec_context
->extradata
,
314 codec_context
->extradata_size
,
318 codec_context
->delay
);
319 if (codec
!= kCodecOpus
) {
320 DCHECK_EQ(av_get_bytes_per_sample(codec_context
->sample_fmt
) * 8,
321 config
->bits_per_channel());
325 void AVStreamToAudioDecoderConfig(
326 const AVStream
* stream
,
327 AudioDecoderConfig
* config
,
329 bool is_encrypted
= false;
330 AVDictionaryEntry
* key
= av_dict_get(stream
->metadata
, "enc_key_id", NULL
, 0);
333 return AVCodecContextToAudioDecoderConfig(
334 stream
->codec
, is_encrypted
, config
, record_stats
);
337 void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig
& config
,
338 AVCodecContext
* codec_context
) {
339 codec_context
->codec_type
= AVMEDIA_TYPE_AUDIO
;
340 codec_context
->codec_id
= AudioCodecToCodecID(config
.codec(),
341 config
.sample_format());
342 codec_context
->sample_fmt
= SampleFormatToAVSampleFormat(
343 config
.sample_format());
345 // TODO(scherkus): should we set |channel_layout|? I'm not sure if FFmpeg uses
346 // said information to decode.
347 codec_context
->channels
=
348 ChannelLayoutToChannelCount(config
.channel_layout());
349 codec_context
->sample_rate
= config
.samples_per_second();
351 if (config
.extra_data()) {
352 codec_context
->extradata_size
= config
.extra_data_size();
353 codec_context
->extradata
= reinterpret_cast<uint8_t*>(
354 av_malloc(config
.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE
));
355 memcpy(codec_context
->extradata
, config
.extra_data(),
356 config
.extra_data_size());
357 memset(codec_context
->extradata
+ config
.extra_data_size(), '\0',
358 FF_INPUT_BUFFER_PADDING_SIZE
);
360 codec_context
->extradata
= NULL
;
361 codec_context
->extradata_size
= 0;
365 void AVStreamToVideoDecoderConfig(
366 const AVStream
* stream
,
367 VideoDecoderConfig
* config
,
369 gfx::Size
coded_size(stream
->codec
->coded_width
, stream
->codec
->coded_height
);
371 // TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true
372 // for now, but may not always be true forever. Fix this in the future.
373 gfx::Rect
visible_rect(stream
->codec
->width
, stream
->codec
->height
);
375 AVRational aspect_ratio
= { 1, 1 };
376 if (stream
->sample_aspect_ratio
.num
)
377 aspect_ratio
= stream
->sample_aspect_ratio
;
378 else if (stream
->codec
->sample_aspect_ratio
.num
)
379 aspect_ratio
= stream
->codec
->sample_aspect_ratio
;
381 VideoCodec codec
= CodecIDToVideoCodec(stream
->codec
->codec_id
);
383 VideoCodecProfile profile
= VIDEO_CODEC_PROFILE_UNKNOWN
;
384 if (codec
== kCodecVP8
)
385 profile
= VP8PROFILE_ANY
;
386 else if (codec
== kCodecVP9
)
387 profile
= VP9PROFILE_ANY
;
389 profile
= ProfileIDToVideoCodecProfile(stream
->codec
->profile
);
391 gfx::Size natural_size
= GetNaturalSize(
392 visible_rect
.size(), aspect_ratio
.num
, aspect_ratio
.den
);
395 // Note the PRESUBMIT_IGNORE_UMA_MAX below, this silences the PRESUBMIT.py
396 // check for uma enum max usage, since we're abusing
397 // UMA_HISTOGRAM_ENUMERATION to report a discrete value.
398 UMA_HISTOGRAM_ENUMERATION("Media.VideoColorRange",
399 stream
->codec
->color_range
,
400 AVCOL_RANGE_NB
); // PRESUBMIT_IGNORE_UMA_MAX
403 VideoFrame::Format format
= PixelFormatToVideoFormat(stream
->codec
->pix_fmt
);
404 if (codec
== kCodecVP9
) {
405 // TODO(tomfinegan): libavcodec doesn't know about VP9.
406 format
= VideoFrame::YV12
;
407 coded_size
= visible_rect
.size();
410 // Pad out |coded_size| for subsampled YUV formats.
411 if (format
!= VideoFrame::YV24
) {
412 coded_size
.set_width((coded_size
.width() + 1) / 2 * 2);
413 if (format
!= VideoFrame::YV16
)
414 coded_size
.set_height((coded_size
.height() + 1) / 2 * 2);
417 bool is_encrypted
= false;
418 AVDictionaryEntry
* key
= av_dict_get(stream
->metadata
, "enc_key_id", NULL
, 0);
422 AVDictionaryEntry
* webm_alpha
=
423 av_dict_get(stream
->metadata
, "alpha_mode", NULL
, 0);
424 if (webm_alpha
&& !strcmp(webm_alpha
->value
, "1")) {
425 format
= VideoFrame::YV12A
;
428 config
->Initialize(codec
,
431 coded_size
, visible_rect
, natural_size
,
432 stream
->codec
->extradata
, stream
->codec
->extradata_size
,
437 void VideoDecoderConfigToAVCodecContext(
438 const VideoDecoderConfig
& config
,
439 AVCodecContext
* codec_context
) {
440 codec_context
->codec_type
= AVMEDIA_TYPE_VIDEO
;
441 codec_context
->codec_id
= VideoCodecToCodecID(config
.codec());
442 codec_context
->profile
= VideoCodecProfileToProfileID(config
.profile());
443 codec_context
->coded_width
= config
.coded_size().width();
444 codec_context
->coded_height
= config
.coded_size().height();
445 codec_context
->pix_fmt
= VideoFormatToPixelFormat(config
.format());
447 if (config
.extra_data()) {
448 codec_context
->extradata_size
= config
.extra_data_size();
449 codec_context
->extradata
= reinterpret_cast<uint8_t*>(
450 av_malloc(config
.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE
));
451 memcpy(codec_context
->extradata
, config
.extra_data(),
452 config
.extra_data_size());
453 memset(codec_context
->extradata
+ config
.extra_data_size(), '\0',
454 FF_INPUT_BUFFER_PADDING_SIZE
);
456 codec_context
->extradata
= NULL
;
457 codec_context
->extradata_size
= 0;
461 ChannelLayout
ChannelLayoutToChromeChannelLayout(int64_t layout
, int channels
) {
463 case AV_CH_LAYOUT_MONO
:
464 return CHANNEL_LAYOUT_MONO
;
465 case AV_CH_LAYOUT_STEREO
:
466 return CHANNEL_LAYOUT_STEREO
;
467 case AV_CH_LAYOUT_2_1
:
468 return CHANNEL_LAYOUT_2_1
;
469 case AV_CH_LAYOUT_SURROUND
:
470 return CHANNEL_LAYOUT_SURROUND
;
471 case AV_CH_LAYOUT_4POINT0
:
472 return CHANNEL_LAYOUT_4_0
;
473 case AV_CH_LAYOUT_2_2
:
474 return CHANNEL_LAYOUT_2_2
;
475 case AV_CH_LAYOUT_QUAD
:
476 return CHANNEL_LAYOUT_QUAD
;
477 case AV_CH_LAYOUT_5POINT0
:
478 return CHANNEL_LAYOUT_5_0
;
479 case AV_CH_LAYOUT_5POINT1
:
480 return CHANNEL_LAYOUT_5_1
;
481 case AV_CH_LAYOUT_5POINT0_BACK
:
482 return CHANNEL_LAYOUT_5_0_BACK
;
483 case AV_CH_LAYOUT_5POINT1_BACK
:
484 return CHANNEL_LAYOUT_5_1_BACK
;
485 case AV_CH_LAYOUT_7POINT0
:
486 return CHANNEL_LAYOUT_7_0
;
487 case AV_CH_LAYOUT_7POINT1
:
488 return CHANNEL_LAYOUT_7_1
;
489 case AV_CH_LAYOUT_7POINT1_WIDE
:
490 return CHANNEL_LAYOUT_7_1_WIDE
;
491 case AV_CH_LAYOUT_STEREO_DOWNMIX
:
492 return CHANNEL_LAYOUT_STEREO_DOWNMIX
;
493 case AV_CH_LAYOUT_2POINT1
:
494 return CHANNEL_LAYOUT_2POINT1
;
495 case AV_CH_LAYOUT_3POINT1
:
496 return CHANNEL_LAYOUT_3_1
;
497 case AV_CH_LAYOUT_4POINT1
:
498 return CHANNEL_LAYOUT_4_1
;
499 case AV_CH_LAYOUT_6POINT0
:
500 return CHANNEL_LAYOUT_6_0
;
501 case AV_CH_LAYOUT_6POINT0_FRONT
:
502 return CHANNEL_LAYOUT_6_0_FRONT
;
503 case AV_CH_LAYOUT_HEXAGONAL
:
504 return CHANNEL_LAYOUT_HEXAGONAL
;
505 case AV_CH_LAYOUT_6POINT1
:
506 return CHANNEL_LAYOUT_6_1
;
507 case AV_CH_LAYOUT_6POINT1_BACK
:
508 return CHANNEL_LAYOUT_6_1_BACK
;
509 case AV_CH_LAYOUT_6POINT1_FRONT
:
510 return CHANNEL_LAYOUT_6_1_FRONT
;
511 case AV_CH_LAYOUT_7POINT0_FRONT
:
512 return CHANNEL_LAYOUT_7_0_FRONT
;
513 #ifdef AV_CH_LAYOUT_7POINT1_WIDE_BACK
514 case AV_CH_LAYOUT_7POINT1_WIDE_BACK
:
515 return CHANNEL_LAYOUT_7_1_WIDE_BACK
;
517 case AV_CH_LAYOUT_OCTAGONAL
:
518 return CHANNEL_LAYOUT_OCTAGONAL
;
520 // FFmpeg channel_layout is 0 for .wav and .mp3. Attempt to guess layout
521 // based on the channel count.
522 return GuessChannelLayout(channels
);
526 VideoFrame::Format
PixelFormatToVideoFormat(PixelFormat pixel_format
) {
527 switch (pixel_format
) {
528 case PIX_FMT_YUV422P
:
529 return VideoFrame::YV16
;
530 case PIX_FMT_YUV444P
:
531 return VideoFrame::YV24
;
532 case PIX_FMT_YUV420P
:
533 return VideoFrame::YV12
;
534 case PIX_FMT_YUVJ420P
:
535 return VideoFrame::YV12J
;
536 case PIX_FMT_YUVA420P
:
537 return VideoFrame::YV12A
;
539 DVLOG(1) << "Unsupported PixelFormat: " << pixel_format
;
541 return VideoFrame::UNKNOWN
;
544 PixelFormat
VideoFormatToPixelFormat(VideoFrame::Format video_format
) {
545 switch (video_format
) {
546 case VideoFrame::YV16
:
547 return PIX_FMT_YUV422P
;
548 case VideoFrame::YV12
:
549 return PIX_FMT_YUV420P
;
550 case VideoFrame::YV12J
:
551 return PIX_FMT_YUVJ420P
;
552 case VideoFrame::YV12A
:
553 return PIX_FMT_YUVA420P
;
554 case VideoFrame::YV24
:
555 return PIX_FMT_YUV444P
;
557 DVLOG(1) << "Unsupported VideoFrame::Format: " << video_format
;
562 bool FFmpegUTCDateToTime(const char* date_utc
,
567 std::vector
<std::string
> fields
;
568 std::vector
<std::string
> date_fields
;
569 std::vector
<std::string
> time_fields
;
570 base::Time::Exploded exploded
;
571 exploded
.millisecond
= 0;
573 // TODO(acolwell): Update this parsing code when FFmpeg returns sub-second
575 if ((Tokenize(date_utc
, " ", &fields
) == 2) &&
576 (Tokenize(fields
[0], "-", &date_fields
) == 3) &&
577 (Tokenize(fields
[1], ":", &time_fields
) == 3) &&
578 base::StringToInt(date_fields
[0], &exploded
.year
) &&
579 base::StringToInt(date_fields
[1], &exploded
.month
) &&
580 base::StringToInt(date_fields
[2], &exploded
.day_of_month
) &&
581 base::StringToInt(time_fields
[0], &exploded
.hour
) &&
582 base::StringToInt(time_fields
[1], &exploded
.minute
) &&
583 base::StringToInt(time_fields
[2], &exploded
.second
)) {
584 base::Time parsed_time
= base::Time::FromUTCExploded(exploded
);
585 if (parsed_time
.is_null())